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

Restyle Add support for re-using CASE sessions #17415

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
12 changes: 11 additions & 1 deletion examples/chip-tool/commands/tests/TestCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,17 @@ CHIP_ERROR TestCommand::RunCommand()

CHIP_ERROR TestCommand::WaitForCommissionee(chip::NodeId nodeId)
{
CurrentCommissioner().ReleaseOperationalDevice(nodeId);
chip::FabricIndex fabricIndex;

ReturnErrorOnFailure(CurrentCommissioner().GetFabricIndex(&fabricIndex));

//
// There's a chance the commissionee may have rebooted before this call here as part of a test flow
// or is just starting out fresh outright. Let's make sure we're not re-using any cached CASE sessions
// that will now be stale and mismatched with the peer, causing subsequent interactions to fail.
//
CurrentCommissioner().SessionMgr()->ExpireAllPairings(nodeId, fabricIndex);

return CurrentCommissioner().GetConnectedDevice(nodeId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback);
}

Expand Down
198 changes: 86 additions & 112 deletions examples/tv-casting-app/linux/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,6 @@
#include <transport/raw/PeerAddress.h>
#include <zap-generated/CHIPClusters.h>

#if defined(ENABLE_CHIP_SHELL)
#include "CastingShellCommands.h"
#include <lib/shell/Engine.h>
#include <thread>
#endif

#include <list>
#include <string>

Expand All @@ -57,10 +51,6 @@ using chip::ArgParser::OptionDef;
using chip::ArgParser::OptionSet;
using namespace chip::app::Clusters::ContentLauncher::Commands;

#if defined(ENABLE_CHIP_SHELL)
using chip::Shell::Engine;
#endif

struct TVExampleDeviceType
{
const char * name;
Expand Down Expand Up @@ -139,17 +129,6 @@ CHIP_ERROR InitBindingHandlers()
return CHIP_NO_ERROR;
}

#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
void HandleUDCSendExpiration(System::Layer * aSystemLayer, void * context)
{
Dnssd::DiscoveredNodeData * selectedCommissioner = (Dnssd::DiscoveredNodeData *) context;

// Send User Directed commissioning request
ReturnOnFailure(Server::GetInstance().SendUserDirectedCommissioningRequest(chip::Transport::PeerAddress::UDP(
selectedCommissioner->ipAddress[0], selectedCommissioner->port, selectedCommissioner->interfaceId)));
}
#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT

/**
* Enters commissioning mode, opens commissioning window, logs onboarding payload.
* If non-null selectedCommissioner is provided, sends user directed commissioning
Expand Down Expand Up @@ -179,25 +158,31 @@ void PrepareForCommissioning(const Dnssd::DiscoveredNodeData * selectedCommissio
if (selectedCommissioner != nullptr)
{
// Send User Directed commissioning request
// Wait 1 second to allow our commissionee DNS records to publish (needed on Mac)
int32_t expiration = 1;
ReturnOnFailure(DeviceLayer::SystemLayer().StartTimer(System::Clock::Seconds32(expiration), HandleUDCSendExpiration,
(void *) selectedCommissioner));
}
else
{
ChipLogProgress(AppServer, "To run discovery again, enter: cast discover");
ReturnOnFailure(Server::GetInstance().SendUserDirectedCommissioningRequest(chip::Transport::PeerAddress::UDP(
selectedCommissioner->ipAddress[0], selectedCommissioner->port, selectedCommissioner->interfaceId)));
}
#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
}

#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
CHIP_ERROR SendUDC(chip::Transport::PeerAddress commissioner)
/**
* Accepts user input of selected commissioner and calls PrepareForCommissioning with
* the selected commissioner
*/
void RequestUserDirectedCommissioning(System::SocketEvents events, intptr_t data)
{
PrepareForCommissioning();
return Server::GetInstance().SendUserDirectedCommissioningRequest(commissioner);
// Accept user selection for commissioner to request commissioning from.
// Assuming kernel has line buffering, this will unblock on '\n' character
// on stdin i.e. when user hits 'Enter'
int selectedCommissionerNumber = CHIP_DEVICE_CONFIG_MAX_DISCOVERED_NODES;
scanf("%d", &selectedCommissionerNumber);
printf("%d\n", selectedCommissionerNumber);
chip::DeviceLayer::SystemLayerSockets().StopWatchingSocket(&gToken);

const Dnssd::DiscoveredNodeData * selectedCommissioner =
gCommissionableNodeController.GetDiscoveredCommissioner(selectedCommissionerNumber - 1);
VerifyOrReturn(selectedCommissioner != nullptr, ChipLogError(AppServer, "No such commissioner!"));
PrepareForCommissioning(selectedCommissioner);
}
#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT

void InitCommissioningFlow(intptr_t commandArg)
{
Expand All @@ -209,7 +194,7 @@ void InitCommissioningFlow(intptr_t commandArg)
const Dnssd::DiscoveredNodeData * commissioner = gCommissionableNodeController.GetDiscoveredCommissioner(i);
if (commissioner != nullptr)
{
ChipLogProgress(AppServer, "Discovered Commissioner #%d", commissionerCount++);
ChipLogProgress(AppServer, "Discovered Commissioner #%d", ++commissionerCount);
commissioner->LogDetail();
}
}
Expand All @@ -219,7 +204,14 @@ void InitCommissioningFlow(intptr_t commandArg)
ChipLogProgress(AppServer, "%d commissioner(s) discovered. Select one (by number# above) to request commissioning from: ",
commissionerCount);

ChipLogProgress(AppServer, "Example: cast request 0");
// Setup for async/non-blocking user input from stdin
int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
VerifyOrReturn(fcntl(0, F_SETFL, flags | O_NONBLOCK) == 0,
ChipLogError(AppServer, "Could not set non-blocking mode for user input!"));
ReturnOnFailure(chip::DeviceLayer::SystemLayerSockets().StartWatchingSocket(STDIN_FILENO, &gToken));
ReturnOnFailure(
chip::DeviceLayer::SystemLayerSockets().SetCallback(gToken, RequestUserDirectedCommissioning, (intptr_t) NULL));
ReturnOnFailure(chip::DeviceLayer::SystemLayerSockets().RequestCallbackOnPendingRead(gToken));
}
else
{
Expand All @@ -228,29 +220,6 @@ void InitCommissioningFlow(intptr_t commandArg)
}
}

CHIP_ERROR DiscoverCommissioners()
{
// Send discover commissioners request
ReturnErrorOnFailure(gCommissionableNodeController.DiscoverCommissioners(gDiscoveryFilter));

// Give commissioners some time to respond and then ScheduleWork to initiate commissioning
return DeviceLayer::SystemLayer().StartTimer(
chip::System::Clock::Milliseconds32(kCommissionerDiscoveryTimeoutInMs),
[](System::Layer *, void *) { chip::DeviceLayer::PlatformMgr().ScheduleWork(InitCommissioningFlow); }, nullptr);
}

CHIP_ERROR RequestCommissioning(int index)
{
const Dnssd::DiscoveredNodeData * selectedCommissioner = gCommissionableNodeController.GetDiscoveredCommissioner(index);
if (selectedCommissioner == nullptr)
{
ChipLogError(AppServer, "No such commissioner with index %d exists", index);
return CHIP_ERROR_INVALID_ARGUMENT;
}
PrepareForCommissioning(selectedCommissioner);
return CHIP_NO_ERROR;
}

void OnContentLauncherSuccessResponse(void * context, const LaunchResponse::DecodableType & response)
{
ChipLogProgress(AppServer, "ContentLauncher: Default Success Response");
Expand Down Expand Up @@ -332,6 +301,10 @@ class TargetEndpointInfo
class TargetVideoPlayerInfo
{
public:
TargetVideoPlayerInfo() :
mOnConnectedCallback(HandleDeviceConnected, this), mOnConnectionFailureCallback(HandleDeviceConnectionFailure, this)
{}

bool IsInitialized() { return mInitialized; }

CHIP_ERROR Initialize(NodeId nodeId, FabricIndex fabricIndex)
Expand Down Expand Up @@ -359,21 +332,30 @@ class TargetVideoPlayerInfo
.clientPool = &gCASEClientPool,
};

PeerId peerID = fabric->GetPeerIdForNode(nodeId);
mOperationalDeviceProxy = chip::Platform::New<chip::OperationalDeviceProxy>(initParams, peerID);
PeerId peerID = fabric->GetPeerIdForNode(nodeId);

//
// TODO: The code here is assuming that we can create an OperationalDeviceProxy instance and attach it immediately
// to a CASE session that just got established to us by the tv-app. While this will work most of the time,
// this is a dangerous assumption to make since it is entirely possible for that secure session to have been
// evicted in the time since that session was established to the point here when we desire to interact back
// with that peer. If that is the case, our `OnConnected` callback will not get invoked syncronously and
// mOperationalDeviceProxy will still have a value of null, triggering the check below to fail.
//
mOperationalDeviceProxy = nullptr;
CHIP_ERROR err =
server->GetCASESessionManager()->FindOrEstablishSession(peerID, &mOnConnectedCallback, &mOnConnectionFailureCallback);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "Could not establish a session to the peer");
return err;
}

// TODO: figure out why this doesn't work so that we can remove OperationalDeviceProxy creation above,
// and remove the FindSecureSessionForNode and SetConnectedSession calls below
// mOperationalDeviceProxy = server->GetCASESessionManager()->FindExistingSession(nodeId);
if (mOperationalDeviceProxy == nullptr)
{
ChipLogError(AppServer, "Failed in creating an instance of OperationalDeviceProxy");
ChipLogError(AppServer, "Failed to find an existing instance of OperationalDeviceProxy to the peer");
return CHIP_ERROR_INVALID_ARGUMENT;
}
ChipLogError(AppServer, "Created an instance of OperationalDeviceProxy");

SessionHandle handle = server->GetSecureSessionManager().FindSecureSessionForNode(nodeId);
mOperationalDeviceProxy->SetConnectedSession(handle);

mInitialized = true;
return CHIP_NO_ERROR;
Expand Down Expand Up @@ -451,12 +433,27 @@ class TargetVideoPlayerInfo
}

private:
static void HandleDeviceConnected(void * context, OperationalDeviceProxy * device)
{
TargetVideoPlayerInfo * _this = static_cast<TargetVideoPlayerInfo *>(context);
_this->mOperationalDeviceProxy = device;
}

static void HandleDeviceConnectionFailure(void * context, PeerId peerId, CHIP_ERROR error)
{
TargetVideoPlayerInfo * _this = static_cast<TargetVideoPlayerInfo *>(context);
_this->mOperationalDeviceProxy = nullptr;
}

static constexpr size_t kMaxNumberOfEndpoints = 5;
TargetEndpointInfo mEndpoints[kMaxNumberOfEndpoints];
NodeId mNodeId;
FabricIndex mFabricIndex;
OperationalDeviceProxy * mOperationalDeviceProxy;

Callback::Callback<OnDeviceConnected> mOnConnectedCallback;
Callback::Callback<OnDeviceConnectionFailure> mOnConnectionFailureCallback;

bool mInitialized = false;
};
TargetVideoPlayerInfo gTargetVideoPlayerInfo;
Expand Down Expand Up @@ -513,7 +510,6 @@ void ReadServerClusters(EndpointId endpointId)

void ReadServerClustersForNode(NodeId nodeId)
{
ChipLogProgress(NotSpecified, "ReadServerClustersForNode nodeId=0x" ChipLogFormatX64, ChipLogValueX64(nodeId));
for (const auto & binding : BindingTable::GetInstance())
{
ChipLogProgress(NotSpecified,
Expand All @@ -527,42 +523,10 @@ void ReadServerClustersForNode(NodeId nodeId)
{
ReadServerClusters(binding.remote);
}
else
{
TargetEndpointInfo * endpointInfo = gTargetVideoPlayerInfo.GetEndpoint(binding.remote);
if (endpointInfo != nullptr && endpointInfo->IsInitialized())
{
endpointInfo->PrintInfo();
}
}
}
}
}

CHIP_ERROR ContentLauncherLaunchURL(const char * contentUrl, const char * contentDisplayStr)
{
OperationalDeviceProxy * operationalDeviceProxy = gTargetVideoPlayerInfo.GetOperationalDeviceProxy();
if (operationalDeviceProxy == nullptr)
{
ChipLogError(AppServer, "Failed in getting an instance of OperationalDeviceProxy");
return CHIP_ERROR_PEER_NODE_NOT_FOUND;
}

ContentLauncherCluster cluster;
CHIP_ERROR err = cluster.Associate(operationalDeviceProxy, kTvEndpoint);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "Associate() failed: %" CHIP_ERROR_FORMAT, err.Format());
return err;
}
LaunchURL::Type request;
request.contentURL = chip::CharSpan::fromCharString(contentUrl);
request.displayString = Optional<CharSpan>(chip::CharSpan::fromCharString(contentDisplayStr));
request.brandingInformation = MakeOptional(chip::app::Clusters::ContentLauncher::Structs::BrandingInformation::Type());
cluster.InvokeCommand(request, nullptr, OnContentLauncherSuccessResponse, OnContentLauncherFailureResponse);
return CHIP_NO_ERROR;
}

void DeviceEventCallback(const DeviceLayer::ChipDeviceEvent * event, intptr_t arg)
{
if (event->Type == DeviceLayer::DeviceEventType::kBindingsChangedViaCluster)
Expand All @@ -577,7 +541,26 @@ void DeviceEventCallback(const DeviceLayer::ChipDeviceEvent * event, intptr_t ar
ReturnOnFailure(gTargetVideoPlayerInfo.Initialize(event->CommissioningComplete.PeerNodeId,
event->CommissioningComplete.PeerFabricIndex));

ContentLauncherLaunchURL(kContentUrl, kContentDisplayStr);
OperationalDeviceProxy * operationalDeviceProxy = gTargetVideoPlayerInfo.GetOperationalDeviceProxy();
if (operationalDeviceProxy == nullptr)
{
ChipLogError(AppServer, "Failed in getting an instance of OperationalDeviceProxy");
return;
}

ContentLauncherCluster cluster;
CHIP_ERROR err = cluster.Associate(operationalDeviceProxy, kTvEndpoint);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "Associate() failed: %" CHIP_ERROR_FORMAT, err.Format());
return;
}
LaunchURL::Type request;
request.contentURL = chip::CharSpan::fromCharString(kContentUrl);
request.displayString = Optional<CharSpan>(chip::CharSpan::fromCharString(kContentDisplayStr));
request.brandingInformation = Optional<chip::app::Clusters::ContentLauncher::Structs::BrandingInformation::Type>(
chip::app::Clusters::ContentLauncher::Structs::BrandingInformation::Type());
cluster.InvokeCommand(request, nullptr, OnContentLauncherSuccessResponse, OnContentLauncherFailureResponse);
}
}

Expand Down Expand Up @@ -627,12 +610,6 @@ LinuxCommissionableDataProvider gCommissionableDataProvider;

int main(int argc, char * argv[])
{
#if defined(ENABLE_CHIP_SHELL)
Engine::Root().Init();
std::thread shellThread([]() { Engine::Root().RunMainLoop(); });
Shell::RegisterCastingCommands();
#endif

CHIP_ERROR err = CHIP_NO_ERROR;

SuccessOrExit(err = chip::Platform::MemoryInit());
Expand Down Expand Up @@ -672,9 +649,6 @@ int main(int argc, char * argv[])

DeviceLayer::PlatformMgr().RunEventLoop();
exit:
#if defined(ENABLE_CHIP_SHELL)
shellThread.join();
#endif
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "Failed to run TV Casting App: %s", ErrorStr(err));
Expand Down
2 changes: 1 addition & 1 deletion src/app/CASESessionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ CHIP_ERROR CASESessionManager::FindOrEstablishSession(PeerId peerId, Callback::C
OperationalDeviceProxy * session = FindExistingSession(peerId);
if (session == nullptr)
{
ChipLogDetail(CASESessionManager, "FindOrEstablishSession: No existing session found");
ChipLogDetail(CASESessionManager, "FindOrEstablishSession: No existing OperationalDeviceProxy instance found");

session = mConfig.devicePool->Allocate(mConfig.sessionInitParams, peerId);

Expand Down
Loading