Linux tv-casting-app v1.3 Commissioner-Generated passcode flow (#33479)
* Linux tv-casting-app v1.3 Commissioner-Generated passcode flow
* Fixing style issues
* Addressed comments by andy31415 and tcarmelveilleux
* Fixing style issue
* Addressed comments by andy31415 and chrisdecenzo
diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterCastingPlayer-JNI.cpp b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterCastingPlayer-JNI.cpp
index 1c4a949..d0409c6 100644
--- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterCastingPlayer-JNI.cpp
+++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterCastingPlayer-JNI.cpp
@@ -24,6 +24,7 @@
#include "core/CastingApp.h" // from tv-casting-common
#include "core/CastingPlayer.h" // from tv-casting-common
#include "core/CastingPlayerDiscovery.h" // from tv-casting-common
+#include "core/ConnectionCallbacks.h" // from tv-casting-common
#include <app/clusters/bindings/BindingManager.h>
#include <app/server/Server.h>
@@ -92,24 +93,36 @@
MatterCastingPlayerJNIMgr().mConnectionSuccessHandler.SetUp(env, jSuccessCallback);
MatterCastingPlayerJNIMgr().mConnectionFailureHandler.SetUp(env, jFailureCallback);
- // TODO: In the following PRs. Add optional CommissionerDeclarationHandler callback parameter.
- castingPlayer->VerifyOrEstablishConnection(
- [](CHIP_ERROR err, CastingPlayer * playerPtr) {
- ChipLogProgress(AppServer, "MatterCastingPlayer-JNI::verifyOrEstablishConnection() ConnectCallback called");
- if (err == CHIP_NO_ERROR)
- {
- ChipLogProgress(AppServer, "MatterCastingPlayer-JNI:: Connected to Casting Player with device ID: %s",
- playerPtr->GetId());
- MatterCastingPlayerJNIMgr().mConnectionSuccessHandler.Handle(nullptr);
- }
- else
- {
- ChipLogError(AppServer, "MatterCastingPlayer-JNI:: ConnectCallback, connection error: %" CHIP_ERROR_FORMAT,
- err.Format());
- MatterCastingPlayerJNIMgr().mConnectionFailureHandler.Handle(err);
- }
- },
- static_cast<unsigned long long int>(commissioningWindowTimeoutSec), idOptions);
+ auto connectCallback = [](CHIP_ERROR err, CastingPlayer * playerPtr) {
+ ChipLogProgress(AppServer, "MatterCastingPlayer-JNI::verifyOrEstablishConnection() ConnectCallback()");
+ if (err == CHIP_NO_ERROR)
+ {
+ ChipLogProgress(AppServer,
+ "MatterCastingPlayer-JNI::verifyOrEstablishConnection() ConnectCallback() Connected to Casting Player "
+ "with device ID: %s",
+ playerPtr->GetId());
+ // The Java jSuccessCallback is expecting a Void v callback parameter which translates to a nullptr. When calling the
+ // Java method from C++ via JNI, passing nullptr is equivalent to passing a Void object in Java.
+ MatterCastingPlayerJNIMgr().mConnectionSuccessHandler.Handle(nullptr);
+ }
+ else
+ {
+ ChipLogError(
+ AppServer,
+ "MatterCastingPlayer-JNI::verifyOrEstablishConnection() ConnectCallback() Connection error: %" CHIP_ERROR_FORMAT,
+ err.Format());
+ MatterCastingPlayerJNIMgr().mConnectionFailureHandler.Handle(err);
+ }
+ };
+
+ // TODO: In the following PRs. Add optional CommissionerDeclarationHandler callback parameter for the Commissioner-Generated
+ // passcode commissioning flow.
+ matter::casting::core::ConnectionCallbacks connectionCallbacks;
+ connectionCallbacks.mOnConnectionComplete = connectCallback;
+
+ // TODO: Verify why commissioningWindowTimeoutSec is a "unsigned long long int" type. Seems too big.
+ castingPlayer->VerifyOrEstablishConnection(connectionCallbacks,
+ static_cast<unsigned long long int>(commissioningWindowTimeoutSec), idOptions);
return support::convertMatterErrorFromCppToJava(CHIP_NO_ERROR);
}
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/MCCastingPlayer.mm b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/MCCastingPlayer.mm
index 1e94b77..f36c517 100644
--- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/MCCastingPlayer.mm
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/MCCastingPlayer.mm
@@ -21,7 +21,8 @@
#import "MCEndpoint_Internal.h"
#import "MCErrorUtils.h"
-#import "core/CastingPlayer.h"
+#import "core/CastingPlayer.h" // from tv-casting-common
+#import "core/ConnectionCallbacks.h" // from tv-casting-common
#import <Foundation/Foundation.h>
@@ -47,7 +48,7 @@
- (void)verifyOrEstablishConnectionWithCompletionBlock:(void (^_Nonnull)(NSError * _Nullable))completion timeout:(long long)timeout desiredEndpointFilter:(MCEndpointFilter * _Nullable)desiredEndpointFilter
{
- ChipLogProgress(AppServer, "MCCastingPlayer.verifyOrEstablishConnectionWithCompletionBlock called");
+ ChipLogProgress(AppServer, "MCCastingPlayer.verifyOrEstablishConnectionWithCompletionBlock() called");
VerifyOrReturn([[MCCastingApp getSharedInstance] isRunning], ChipLogError(AppServer, "MCCastingApp NOT running"));
dispatch_queue_t workQueue = [[MCCastingApp getSharedInstance] getWorkQueue];
@@ -63,18 +64,23 @@
CHIP_ERROR result = idOptions.addTargetAppInfo(targetAppInfo);
if (result != CHIP_NO_ERROR) {
- ChipLogError(AppServer, "MCCastingPlayer.verifyOrEstablishConnectionWithCompletionBlock failed to add targetAppInfo: %" CHIP_ERROR_FORMAT, result.Format());
+ ChipLogError(AppServer, "MCCastingPlayer.verifyOrEstablishConnectionWithCompletionBlock() failed to add targetAppInfo: %" CHIP_ERROR_FORMAT, result.Format());
}
}
- // TODO: In the following PRs. Add optional CommissionerDeclarationHandler callback parameter.
- _cppCastingPlayer->VerifyOrEstablishConnection(
- [completion](CHIP_ERROR err, matter::casting::core::CastingPlayer * castingPlayer) {
- dispatch_queue_t clientQueue = [[MCCastingApp getSharedInstance] getClientQueue];
- dispatch_async(clientQueue, ^{
- completion(err == CHIP_NO_ERROR ? nil : [MCErrorUtils NSErrorFromChipError:err]);
- });
- }, timeout, idOptions);
+ void (^connectCallback)(CHIP_ERROR, matter::casting::core::CastingPlayer *) = ^(CHIP_ERROR err, matter::casting::core::CastingPlayer * castingPlayer) {
+ ChipLogProgress(AppServer, "MCCastingPlayer.verifyOrEstablishConnectionWithCompletionBlock() ConnectCallback()");
+ dispatch_queue_t clientQueue = [[MCCastingApp getSharedInstance] getClientQueue];
+ dispatch_async(clientQueue, ^{
+ completion(err == CHIP_NO_ERROR ? nil : [MCErrorUtils NSErrorFromChipError:err]);
+ });
+ };
+
+ matter::casting::core::ConnectionCallbacks connectionCallbacks;
+ connectionCallbacks.mOnConnectionComplete = connectCallback;
+
+ // TODO: In the following PRs. Add optional CommissionerDeclarationHandler callback parameter for the Commissioner-Generated passcode commissioning flow.
+ _cppCastingPlayer->VerifyOrEstablishConnection(connectionCallbacks, timeout, idOptions);
});
}
diff --git a/examples/tv-casting-app/linux/simple-app-helper.cpp b/examples/tv-casting-app/linux/simple-app-helper.cpp
index ceb6623..49f006a 100644
--- a/examples/tv-casting-app/linux/simple-app-helper.cpp
+++ b/examples/tv-casting-app/linux/simple-app-helper.cpp
@@ -1,6 +1,6 @@
/*
*
- * Copyright (c) 2023 Project CHIP Authors
+ * Copyright (c) 2023-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.
@@ -16,6 +16,7 @@
*/
#include "simple-app-helper.h"
+#include "../tv-casting-common/core/ConnectionCallbacks.h"
#include "clusters/Clusters.h"
#include "app/clusters/bindings/BindingManager.h"
@@ -28,11 +29,14 @@
#include <lib/support/CHIPMem.h>
#include <lib/support/CodeUtils.h>
#include <platform/CHIPDeviceLayer.h>
+#include <platform/TestOnlyCommissionableDataProvider.h>
// VendorId of the Endpoint on the CastingPlayer that the CastingApp desires to interact with after connection
const uint16_t kDesiredEndpointVendorId = 65521;
DiscoveryDelegateImpl * DiscoveryDelegateImpl::_discoveryDelegateImpl = nullptr;
+bool gAwaitingCommissionerPasscodeInput = false;
+std::shared_ptr<matter::casting::core::CastingPlayer> targetCastingPlayer;
DiscoveryDelegateImpl * DiscoveryDelegateImpl::GetInstance()
{
@@ -45,14 +49,17 @@
void DiscoveryDelegateImpl::HandleOnAdded(matter::casting::memory::Strong<matter::casting::core::CastingPlayer> player)
{
- ChipLogProgress(AppServer, "DiscoveryDelegateImpl::HandleOnAdded() called");
+ ChipLogProgress(AppServer, "DiscoveryDelegateImpl::HandleOnAdded()");
if (commissionersCount == 0)
{
- ChipLogProgress(AppServer, "Select discovered Casting Player (start index = 0) to request commissioning");
- ChipLogProgress(AppServer, "Include the cgp flag to attempt the Commissioner-Generated Passcode commissioning flow");
-
- ChipLogProgress(AppServer, "Example1 Commissionee Passcode: cast request 0");
- ChipLogProgress(AppServer, "Example2 Commissioner Passcode: cast request 0 cgp");
+ ChipLogProgress(AppServer, "---- Awaiting user input ----");
+ ChipLogProgress(AppServer, "Select a discovered Casting Player (start index = 0) to request commissioning.");
+ ChipLogProgress(
+ AppServer,
+ "Include the commissioner-generated-passcode flag to attempt the Commissioner-Generated passcode commissioning flow.");
+ ChipLogProgress(AppServer, "Example 1 Commissionee Passcode: cast request 0");
+ ChipLogProgress(AppServer, "Example 2 Commissioner Passcode: cast request 0 commissioner-generated-passcode");
+ ChipLogProgress(AppServer, "---- Awaiting user input ----");
}
ChipLogProgress(AppServer, "Discovered CastingPlayer #%d", commissionersCount);
++commissionersCount;
@@ -168,22 +175,98 @@
kMinIntervalFloorSeconds, kMaxIntervalCeilingSeconds);
}
+CHIP_ERROR InitCommissionableDataProvider(LinuxCommissionableDataProvider & provider, LinuxDeviceOptions & options)
+{
+ ChipLogProgress(Discovery, "InitCommissionableDataProvider()");
+ chip::Optional<uint32_t> setupPasscode;
+
+ if (options.payload.setUpPINCode != 0)
+ {
+ setupPasscode.SetValue(options.payload.setUpPINCode);
+ ChipLogProgress(Discovery, "InitCommissionableDataProvider() using setupPasscode: %d", setupPasscode.Value());
+ }
+ else if (!options.spake2pVerifier.HasValue())
+ {
+ uint32_t defaultTestPasscode = 0;
+ chip::DeviceLayer::TestOnlyCommissionableDataProvider TestOnlyCommissionableDataProvider;
+ VerifyOrDie(TestOnlyCommissionableDataProvider.GetSetupPasscode(defaultTestPasscode) == CHIP_NO_ERROR);
+
+ ChipLogError(Support,
+ "InitCommissionableDataProvider() *** WARNING: Using temporary passcode %u due to no neither --passcode or "
+ "--spake2p-verifier-base64 "
+ "given on command line. This is temporary and will be deprecated. Please update your scripts "
+ "to explicitly configure onboarding credentials. ***",
+ static_cast<unsigned>(defaultTestPasscode));
+ setupPasscode.SetValue(defaultTestPasscode);
+ options.payload.setUpPINCode = defaultTestPasscode;
+ }
+ else
+ {
+ ChipLogError(Support,
+ "InitCommissionableDataProvider() *** WARNING: Passcode is 0, so will be ignored, and verifier will take "
+ "over. Onboarding payload printed for debug will be invalid, but if the onboarding payload had been given "
+ "properly to the commissioner later, PASE will succeed. ***");
+ }
+
+ // Default to the minimum PBKDF iterations (1,000) for this example implementation. For TV devices and TV casting app production
+ // implementations, you should use a higher number of PBKDF iterations to enhance security. The default minimum iterations are
+ // not sufficient against brute-force and rainbow table attacks. Increasing the number of iterations will increase the
+ // computational time required to derive the key. This can slow down the authentication process, especially on devices with
+ // limited processing power like a Raspberry Pi 4. For a production implementation, you should measure the actual performance on
+ // the target device.
+ uint32_t spake2pIterationCount =
+ chip::Crypto::kSpake2p_Min_PBKDF_Iterations; // 1,000 - Hypothetical key derivation time: ~20 milliseconds (ms).
+ // uint32_t spake2pIterationCount = chip::Crypto::kSpake2p_Max_PBKDF_Iterations; // 100,000 - Hypothetical key derivation time:
+ // ~2 seconds.
+ if (options.spake2pIterations == 1000)
+ {
+ spake2pIterationCount = options.spake2pIterations;
+ ChipLogError(Support,
+ "InitCommissionableDataProvider() *** WARNING: PASE PBKDF iterations provided are the minimum allowable: %u. "
+ "Increase for production use to enhance security. ***",
+ static_cast<unsigned>(spake2pIterationCount));
+ }
+ else if ((options.spake2pIterations > 1000))
+ {
+ spake2pIterationCount = options.spake2pIterations;
+ ChipLogProgress(Support, "InitCommissionableDataProvider() PASE PBKDF iterations set to: %u.",
+ static_cast<unsigned>(spake2pIterationCount));
+ }
+ else
+ {
+ ChipLogError(Support,
+ "InitCommissionableDataProvider() *** WARNING: PASE PBKDF iterations set to the minimum allowable: %u. "
+ "Increase for production use to enhance security. ***",
+ static_cast<unsigned>(spake2pIterationCount));
+ }
+
+ return provider.Init(options.spake2pVerifier, options.spake2pSalt, spake2pIterationCount, setupPasscode,
+ options.payload.discriminator.GetLongValue());
+}
+
void ConnectionHandler(CHIP_ERROR err, matter::casting::core::CastingPlayer * castingPlayer)
{
- VerifyOrReturn(err == CHIP_NO_ERROR,
- ChipLogProgress(AppServer,
- "ConnectionHandler(): Failed to connect to CastingPlayer(ID: %s) with err %" CHIP_ERROR_FORMAT,
- castingPlayer->GetId(), err.Format()));
+ ChipLogProgress(AppServer, "simple-app-helper.cpp::ConnectionHandler()");
- ChipLogProgress(AppServer, "ConnectionHandler(): Successfully connected to CastingPlayer(ID: %s)", castingPlayer->GetId());
- ChipLogProgress(AppServer, "ConnectionHandler(): Triggering demo interactions with CastingPlayer(ID: %s)",
+ // For a connection failure, called back with an error and nullptr.
+ VerifyOrReturn(
+ err == CHIP_NO_ERROR,
+ ChipLogProgress(
+ AppServer,
+ "simple-app-helper.cpp::ConnectionHandler(): Failed to connect to CastingPlayer (ID: %s) with err %" CHIP_ERROR_FORMAT,
+ targetCastingPlayer->GetId(), err.Format()));
+
+ ChipLogProgress(AppServer, "simple-app-helper.cpp::ConnectionHandler(): Successfully connected to CastingPlayer (ID: %s)",
+ castingPlayer->GetId());
+ ChipLogProgress(AppServer,
+ "simple-app-helper.cpp::ConnectionHandler(): Triggering demo interactions with CastingPlayer (ID: %s)",
castingPlayer->GetId());
std::vector<matter::casting::memory::Strong<matter::casting::core::Endpoint>> endpoints = castingPlayer->GetEndpoints();
// Find the desired Endpoint and auto-trigger some Matter Casting demo interactions
auto it = std::find_if(endpoints.begin(), endpoints.end(),
[](const matter::casting::memory::Strong<matter::casting::core::Endpoint> & endpoint) {
- return endpoint->GetVendorId() == 65521;
+ return endpoint->GetVendorId() == kDesiredEndpointVendorId;
});
if (it != endpoints.end())
{
@@ -201,7 +284,27 @@
}
else
{
- ChipLogError(AppServer, "Desired Endpoint not found on the CastingPlayer(ID: %s)", castingPlayer->GetId());
+ ChipLogError(
+ AppServer,
+ "simple-app-helper.cpp::ConnectionHandler():Desired Endpoint Vendor Id (%d) not found on the CastingPlayer (ID: %s)",
+ kDesiredEndpointVendorId, castingPlayer->GetId());
+ }
+}
+
+void CommissionerDeclarationCallback(const chip::Transport::PeerAddress & source,
+ chip::Protocols::UserDirectedCommissioning::CommissionerDeclaration cd)
+{
+ ChipLogProgress(AppServer,
+ "simple-app-helper.cpp::CommissionerDeclarationCallback() called with CommissionerDeclaration message:");
+ cd.DebugLog();
+ if (cd.GetCommissionerPasscode())
+ {
+ ChipLogProgress(AppServer, "---- Awaiting user input ----");
+ ChipLogProgress(AppServer, "Input the Commissioner-Generated passcode displayed on the CastingPlayer UX.");
+ ChipLogProgress(AppServer, "Input 1245678 to use the default passcode.");
+ ChipLogProgress(AppServer, "Example: cast setcommissionerpasscode 12345678");
+ ChipLogProgress(AppServer, "---- Awaiting user input ----");
+ gAwaitingCommissionerPasscodeInput = true;
}
}
@@ -245,28 +348,28 @@
matter::casting::core::CastingPlayerDiscovery::GetInstance()->GetCastingPlayers();
VerifyOrReturnValue(0 <= index && index < castingPlayers.size(), CHIP_ERROR_INVALID_ARGUMENT,
ChipLogError(AppServer, "Invalid casting player index provided: %lu", index));
- std::shared_ptr<matter::casting::core::CastingPlayer> targetCastingPlayer = castingPlayers.at(index);
+ targetCastingPlayer = castingPlayers.at(index);
matter::casting::core::IdentificationDeclarationOptions idOptions;
if (argc == 3)
{
- if (strcmp(argv[2], "cgp") == 0)
+ if (strcmp(argv[2], "commissioner-generated-passcode") == 0)
{
- // Attempt Commissioner-Generated Passcode (cgp) commissioning flow only if the CastingPlayer indicates support for
- // it.
+ // Attempt Commissioner-Generated Passcode (commissioner-generated-passcode) commissioning flow only if the
+ // CastingPlayer indicates support for it.
if (targetCastingPlayer->GetSupportsCommissionerGeneratedPasscode())
{
- ChipLogProgress(
- AppServer,
- "CommandHandler() request %lu cgp. Attempting the Commissioner-Generated Passcode commissioning flow",
- index);
+ ChipLogProgress(AppServer,
+ "CommandHandler() request %lu commissioner-generated-passcode. Attempting the "
+ "Commissioner-Generated Passcode commissioning flow",
+ index);
idOptions.mCommissionerPasscode = true;
}
else
{
ChipLogError(AppServer,
- "CommandHandler() request %lu cgp. Selected CastingPLayer does not support the "
- "Commissioner-Generated Passcode commissioning flow",
+ "CommandHandler() request %lu commissioner-generated-passcode. Selected CastingPLayer does not "
+ "support the Commissioner-Generated Passcode commissioning flow",
index);
}
}
@@ -279,10 +382,67 @@
ChipLogError(AppServer, "CommandHandler() request, failed to add targetAppInfo: %" CHIP_ERROR_FORMAT, result.Format());
}
- targetCastingPlayer->VerifyOrEstablishConnection(ConnectionHandler, matter::casting::core::kCommissioningWindowTimeoutSec,
+ matter::casting::core::ConnectionCallbacks connectionCallbacks;
+ connectionCallbacks.mOnConnectionComplete = ConnectionHandler;
+ // Provide an handler (Optional) for Commissioner's CommissionerDeclaration messages. The CommissionerDeclaration messages
+ // provide information indicating the Commissioner's pre-commissioning state.
+ connectionCallbacks.mCommissionerDeclarationCallback = CommissionerDeclarationCallback;
+
+ targetCastingPlayer->VerifyOrEstablishConnection(connectionCallbacks, matter::casting::core::kCommissioningWindowTimeoutSec,
idOptions);
return CHIP_NO_ERROR;
}
+ if (strcmp(argv[0], "setcommissionerpasscode") == 0)
+ {
+ ChipLogProgress(AppServer, "CommandHandler() setcommissionerpasscode");
+ if (argc < 2)
+ {
+ return PrintAllCommands();
+ }
+ char * eptr;
+ uint32_t passcode = (uint32_t) strtol(argv[1], &eptr, 10);
+ if (gAwaitingCommissionerPasscodeInput)
+ {
+ ChipLogProgress(AppServer, "CommandHandler() setcommissionerpasscode user enterd passcode: %d", passcode);
+ gAwaitingCommissionerPasscodeInput = false;
+
+ // Per connectedhomeip/examples/platform/linux/LinuxCommissionableDataProvider.h: We don't support overriding the
+ // passcode post-init (it is deprecated!). Therefore we need to initiate a new provider with the user entered
+ // Commissioner-generated passcode, and then update the CastigApp's AppParameters to update the commissioning session's
+ // passcode.
+ LinuxDeviceOptions::GetInstance().payload.setUpPINCode = passcode;
+ LinuxCommissionableDataProvider gCommissionableDataProvider;
+ CHIP_ERROR err = CHIP_NO_ERROR;
+ err = InitCommissionableDataProvider(gCommissionableDataProvider, LinuxDeviceOptions::GetInstance());
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogError(AppServer,
+ "CommandHandler() setcommissionerpasscode InitCommissionableDataProvider() err %" CHIP_ERROR_FORMAT,
+ err.Format());
+ }
+ // Update the CommissionableDataProvider stored in this CastingApp's AppParameters and the CommissionableDataProvider to
+ // be used for the commissioning session.
+ err = matter::casting::core::CastingApp::GetInstance()->UpdateCommissionableDataProvider(&gCommissionableDataProvider);
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogError(AppServer,
+ "CommandHandler() setcommissionerpasscode InitCommissionableDataProvider() err %" CHIP_ERROR_FORMAT,
+ err.Format());
+ }
+
+ matter::casting::core::ConnectionCallbacks connectionCallbacks;
+ connectionCallbacks.mOnConnectionComplete = ConnectionHandler;
+
+ // Continue Connecting to the target CastingPlayer with the user entered Commissioner-generated Passcode.
+ targetCastingPlayer->ContinueConnecting(connectionCallbacks, matter::casting::core::kCommissioningWindowTimeoutSec);
+ }
+ else
+ {
+ ChipLogError(
+ AppServer,
+ "CommandHandler() setcommissionerpasscode, no Commissioner-Generated passcode input expected at this time.");
+ }
+ }
if (strcmp(argv[0], "print-bindings") == 0)
{
PrintBindings();
@@ -315,11 +475,15 @@
streamer_printf(sout, " discover Discover Casting Players. Usage: cast discover\r\n");
streamer_printf(sout, " stop-discovery Stop Discovery of Casting Players. Usage: cast stop-discovery\r\n");
streamer_printf(sout,
- " request <index> Request connecting to discovered Casting Player with [index] using the "
- "Commissionee-Generated Passcode commissioning flow. Usage: cast request 0\r\n");
+ " request <index> Request connecting to discovered Casting Player with "
+ "[index] using the Commissionee-Generated passcode commissioning flow. Usage: cast request 0\r\n");
streamer_printf(sout,
- " request <index> cgp Request connecting to discovered Casting Player with [index] using the "
- "Commissioner-Generated Passcode commissioning flow. Usage: cast request 0 cgp\r\n");
+ " request <index> commissioner-generated-passcode Request connecting to discovered Casting Player with "
+ "[index] using the Commissioner-Generated passcode commissioning flow. Usage: cast request 0 cgp\r\n");
+ streamer_printf(sout,
+ " setcommissionerpasscode <passcode> Set the commissioning session's passcode to the "
+ "Commissioner-Generated passcode. Used for the the Commissioner-Generated passcode commissioning flow. Usage: "
+ "cast setcommissionerpasscode 12345678\r\n");
streamer_printf(sout, "\r\n");
return CHIP_NO_ERROR;
diff --git a/examples/tv-casting-app/linux/simple-app-helper.h b/examples/tv-casting-app/linux/simple-app-helper.h
index f8826b5..f3bdc6e 100644
--- a/examples/tv-casting-app/linux/simple-app-helper.h
+++ b/examples/tv-casting-app/linux/simple-app-helper.h
@@ -1,6 +1,6 @@
/*
*
- * Copyright (c) 2023 Project CHIP Authors
+ * Copyright (c) 2023-2024 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,6 +22,8 @@
#include "core/CastingPlayerDiscovery.h"
#include "core/IdentificationDeclarationOptions.h"
#include "core/Types.h"
+#include <LinuxCommissionableDataProvider.h>
+#include <Options.h>
#include <platform/CHIPDeviceLayer.h>
/**
@@ -69,6 +71,12 @@
};
/**
+ * @brief Initializes a LinuxCommissionableDataProvider using configuration options provided via a LinuxDeviceOptions. It first
+ * checks if a setup PIN code is specified; if not, it attempts to use a temporary default passcode.
+ */
+CHIP_ERROR InitCommissionableDataProvider(LinuxCommissionableDataProvider & provider, LinuxDeviceOptions & options);
+
+/**
* @brief Linux tv-casting-app's onCompleted handler for CastingPlayer.VerifyOrEstablishConnection API
*/
void ConnectionHandler(CHIP_ERROR err, matter::casting::core::CastingPlayer * castingPlayer);
diff --git a/examples/tv-casting-app/linux/simple-app.cpp b/examples/tv-casting-app/linux/simple-app.cpp
index 01e3346..41f3391 100644
--- a/examples/tv-casting-app/linux/simple-app.cpp
+++ b/examples/tv-casting-app/linux/simple-app.cpp
@@ -1,6 +1,6 @@
/*
*
- * Copyright (c) 2023 Project CHIP Authors
+ * Copyright (c) 2023-2024 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -45,47 +45,6 @@
// To hold SPAKE2+ verifier, discriminator, passcode
LinuxCommissionableDataProvider gCommissionableDataProvider;
-CHIP_ERROR InitCommissionableDataProvider(LinuxCommissionableDataProvider & provider, LinuxDeviceOptions & options)
-{
- chip::Optional<uint32_t> setupPasscode;
-
- if (options.payload.setUpPINCode != 0)
- {
- setupPasscode.SetValue(options.payload.setUpPINCode);
- }
- else if (!options.spake2pVerifier.HasValue())
- {
- uint32_t defaultTestPasscode = 0;
- chip::DeviceLayer::TestOnlyCommissionableDataProvider TestOnlyCommissionableDataProvider;
- VerifyOrDie(TestOnlyCommissionableDataProvider.GetSetupPasscode(defaultTestPasscode) == CHIP_NO_ERROR);
-
- ChipLogError(Support,
- "*** WARNING: Using temporary passcode %u due to no neither --passcode or --spake2p-verifier-base64 "
- "given on command line. This is temporary and will be deprecated. Please update your scripts "
- "to explicitly configure onboarding credentials. ***",
- static_cast<unsigned>(defaultTestPasscode));
- setupPasscode.SetValue(defaultTestPasscode);
- options.payload.setUpPINCode = defaultTestPasscode;
- }
- else
- {
- // Passcode is 0, so will be ignored, and verifier will take over. Onboarding payload
- // printed for debug will be invalid, but if the onboarding payload had been given
- // properly to the commissioner later, PASE will succeed.
- }
-
- // Default to minimum PBKDF iterations
- uint32_t spake2pIterationCount = chip::Crypto::kSpake2p_Min_PBKDF_Iterations;
- if (options.spake2pIterations != 0)
- {
- spake2pIterationCount = options.spake2pIterations;
- }
- ChipLogError(Support, "PASE PBKDF iterations set to %u", static_cast<unsigned>(spake2pIterationCount));
-
- return provider.Init(options.spake2pVerifier, options.spake2pSalt, spake2pIterationCount, setupPasscode,
- options.payload.discriminator.GetLongValue());
-}
-
/**
* @brief Provides the unique ID that is used by the SDK to generate the Rotating Device ID.
*/
diff --git a/examples/tv-casting-app/tv-casting-common/BUILD.gn b/examples/tv-casting-app/tv-casting-common/BUILD.gn
index a58d272..3899773 100644
--- a/examples/tv-casting-app/tv-casting-common/BUILD.gn
+++ b/examples/tv-casting-app/tv-casting-common/BUILD.gn
@@ -107,6 +107,8 @@
"core/CastingPlayerDiscovery.h",
"core/Command.h",
"core/CommissionerDeclarationHandler.cpp",
+ "core/CommissionerDeclarationHandler.h",
+ "core/ConnectionCallbacks.h",
"core/Endpoint.cpp",
"core/Endpoint.h",
"core/Types.h",
diff --git a/examples/tv-casting-app/tv-casting-common/core/CastingApp.cpp b/examples/tv-casting-app/tv-casting-common/core/CastingApp.cpp
index 7e00013..216d06b 100644
--- a/examples/tv-casting-app/tv-casting-common/core/CastingApp.cpp
+++ b/examples/tv-casting-app/tv-casting-common/core/CastingApp.cpp
@@ -1,6 +1,6 @@
/*
*
- * Copyright (c) 2023 Project CHIP Authors
+ * Copyright (c) 2023-2024 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,6 +19,7 @@
#include "CastingApp.h"
#include "CommissionerDeclarationHandler.h"
+#include "ConnectionCallbacks.h"
#include "support/CastingStore.h"
#include "support/ChipDeviceEventHandler.h"
@@ -85,37 +86,51 @@
return CHIP_NO_ERROR;
}
+CHIP_ERROR CastingApp::UpdateCommissionableDataProvider(chip::DeviceLayer::CommissionableDataProvider * commissionableDataProvider)
+{
+ ChipLogProgress(Discovery, "CastingApp::UpdateCommissionableDataProvider()");
+ chip::DeviceLayer::SetCommissionableDataProvider(commissionableDataProvider);
+ return mAppParameters->SetCommissionableDataProvider(commissionableDataProvider);
+}
+
+void ReconnectHandler(CHIP_ERROR err, matter::casting::core::CastingPlayer * castingPlayer)
+{
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogError(AppServer, "CastingApp::ConnectionHandler() Could not reconnect to CastingPlayer %" CHIP_ERROR_FORMAT,
+ err.Format());
+ }
+ else
+ {
+ ChipLogProgress(AppServer, "CastingApp::ConnectionHandler() Reconnected to CastingPlayer(ID: %s)", castingPlayer->GetId());
+ }
+}
+
CHIP_ERROR CastingApp::Start()
{
- ChipLogProgress(Discovery, "CastingApp::Start() called");
+ ChipLogProgress(Discovery, "CastingApp::Start()");
VerifyOrReturnError(mState == CASTING_APP_NOT_RUNNING, CHIP_ERROR_INCORRECT_STATE);
- // start Matter server
+ // Start Matter server
chip::ServerInitParams * serverInitParams = mAppParameters->GetServerInitParamsProvider()->Get();
VerifyOrReturnError(serverInitParams != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
ReturnErrorOnFailure(chip::Server::GetInstance().Init(*serverInitParams));
- // perform post server startup registrations
+ // Perform post server startup registrations
ReturnErrorOnFailure(PostStartRegistrations());
- // reconnect (or verify connection) to the CastingPlayer that the app was connected to before being stopped, if any
+ // Reconnect (or verify connection) to the CastingPlayer that the app was connected to before being stopped, if any
if (CastingPlayer::GetTargetCastingPlayer() != nullptr)
{
+ matter::casting::core::ConnectionCallbacks connectionCallbacks;
+ connectionCallbacks.mOnConnectionComplete = ReconnectHandler;
+ // Re-connecting to a CastingPLayer does not require a full User Directed Commissioning (UDC) process so
+ // CommissionerDeclaration messages are not expected. Leaving ConnectionCallbacks mCommissionerDeclarationCallback as
+ // nullptr.
ChipLogProgress(
Discovery,
"CastingApp::Start() calling VerifyOrEstablishConnection() to reconnect (or verify connection) to a CastingPlayer");
- CastingPlayer::GetTargetCastingPlayer()->VerifyOrEstablishConnection(
- [](CHIP_ERROR err, matter::casting::core::CastingPlayer * castingPlayer) {
- if (err != CHIP_NO_ERROR)
- {
- ChipLogError(AppServer, "CastingApp::Start Could not reconnect to CastingPlayer %" CHIP_ERROR_FORMAT,
- err.Format());
- }
- else
- {
- ChipLogProgress(AppServer, "CastingApp::Start Reconnected to CastingPlayer(ID: %s)", castingPlayer->GetId());
- }
- });
+ CastingPlayer::GetTargetCastingPlayer()->VerifyOrEstablishConnection(connectionCallbacks);
}
return CHIP_NO_ERROR;
@@ -123,7 +138,7 @@
CHIP_ERROR CastingApp::PostStartRegistrations()
{
- ChipLogProgress(Discovery, "CastingApp::PostStartRegistrations() called");
+ ChipLogProgress(Discovery, "CastingApp::PostStartRegistrations()");
VerifyOrReturnError(mState == CASTING_APP_NOT_RUNNING, CHIP_ERROR_INCORRECT_STATE);
auto & server = chip::Server::GetInstance();
@@ -140,8 +155,12 @@
// Register DeviceEvent Handler
ReturnErrorOnFailure(chip::DeviceLayer::PlatformMgrImpl().AddEventHandler(ChipDeviceEventHandler::Handle, 0));
+ ChipLogProgress(
+ Discovery,
+ "CastingApp::PostStartRegistrations() calling GetUserDirectedCommissioningClient()->SetCommissionerDeclarationHandler()");
#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
- // Set a handler for Commissioner's CommissionerDeclaration messages.
+ // Set a handler for Commissioner's CommissionerDeclaration messages. This is set in
+ // connectedhomeip/src/protocols/user_directed_commissioning/UserDirectedCommissioning.h
chip::Server::GetInstance().GetUserDirectedCommissioningClient()->SetCommissionerDeclarationHandler(
CommissionerDeclarationHandler::GetInstance());
#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
@@ -152,7 +171,7 @@
CHIP_ERROR CastingApp::Stop()
{
- ChipLogProgress(Discovery, "CastingApp::Stop() called");
+ ChipLogProgress(Discovery, "CastingApp::Stop()");
VerifyOrReturnError(mState == CASTING_APP_RUNNING, CHIP_ERROR_INCORRECT_STATE);
#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
diff --git a/examples/tv-casting-app/tv-casting-common/core/CastingApp.h b/examples/tv-casting-app/tv-casting-common/core/CastingApp.h
index f286aad..25ab479 100644
--- a/examples/tv-casting-app/tv-casting-common/core/CastingApp.h
+++ b/examples/tv-casting-app/tv-casting-common/core/CastingApp.h
@@ -53,6 +53,14 @@
CHIP_ERROR Initialize(const matter::casting::support::AppParameters & appParameters);
/**
+ * @brief Update the CommissionableDataProvider stored in this CastingApp's AppParameters and the CommissionableDataProvider to
+ * be used for the commissioning session.
+ * @param commissionableDataProvider the new CommissionableDataProvider to be used for the next commissioning session.
+ *
+ */
+ CHIP_ERROR UpdateCommissionableDataProvider(chip::DeviceLayer::CommissionableDataProvider * commissionableDataProvider);
+
+ /**
* @brief Starts the Matter server that the CastingApp runs on and registers all the necessary delegates
* CastingApp.
* If the CastingApp was previously connected to a CastingPlayer and then Stopped by calling the Stop()
diff --git a/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp b/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp
index a712c17..b3075be 100644
--- a/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp
+++ b/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp
@@ -29,7 +29,9 @@
CastingPlayer * CastingPlayer::mTargetCastingPlayer = nullptr;
-void CastingPlayer::VerifyOrEstablishConnection(ConnectCallback onCompleted, unsigned long long int commissioningWindowTimeoutSec,
+// TODO: Verify why commissioningWindowTimeoutSec is a "unsigned long long int" type. Seems too big.
+void CastingPlayer::VerifyOrEstablishConnection(ConnectionCallbacks connectionCallbacks,
+ unsigned long long int commissioningWindowTimeoutSec,
IdentificationDeclarationOptions idOptions)
{
ChipLogProgress(AppServer, "CastingPlayer::VerifyOrEstablishConnection() called");
@@ -46,12 +48,30 @@
ChipLogError(
AppServer,
"CastingPlayer::VerifyOrEstablishConnection() called while already connecting/connected to this CastingPlayer"));
+ VerifyOrExit(
+ connectionCallbacks.mOnConnectionComplete != nullptr,
+ ChipLogError(AppServer,
+ "CastingPlayer::VerifyOrEstablishConnection() ConnectionCallbacks.mOnConnectionComplete was not provided"));
mConnectionState = CASTING_PLAYER_CONNECTING;
- mOnCompleted = onCompleted;
+ mOnCompleted = connectionCallbacks.mOnConnectionComplete;
mCommissioningWindowTimeoutSec = commissioningWindowTimeoutSec;
mTargetCastingPlayer = this;
mIdOptions = idOptions;
+ // Register the handler for Commissioner's CommissionerDeclaration messages. The CommissionerDeclaration messages provide
+ // information indicating the Commissioner's pre-commissioning state.
+ if (connectionCallbacks.mCommissionerDeclarationCallback != nullptr)
+ {
+ matter::casting::core::CommissionerDeclarationHandler::GetInstance()->SetCommissionerDeclarationCallback(
+ connectionCallbacks.mCommissionerDeclarationCallback);
+ }
+ else
+ {
+ ChipLogProgress(
+ AppServer,
+ "CastingPlayer::VerifyOrEstablishConnection() CommissionerDeclarationCallback not provided in ConnectionCallbacks");
+ }
+
// If *this* CastingPlayer was previously connected to, its nodeId, fabricIndex and other attributes should be present
// in the CastingStore cache. If that is the case, AND, the cached data contains the endpoint desired by the client, if any,
// as per IdentificationDeclarationOptions.mTargetAppInfos, simply Find or Re-establish the CASE session and return early.
@@ -72,7 +92,7 @@
"CastingPlayer::VerifyOrEstablishConnection() calling FindOrEstablishSession on cached CastingPlayer");
*this = cachedCastingPlayers[index];
mConnectionState = CASTING_PLAYER_CONNECTING;
- mOnCompleted = onCompleted;
+ mOnCompleted = connectionCallbacks.mOnConnectionComplete;
mCommissioningWindowTimeoutSec = commissioningWindowTimeoutSec;
FindOrEstablishSession(
@@ -118,9 +138,33 @@
}
else
{
+ ChipLogProgress(AppServer,
+ "CastingPlayer::VerifyOrEstablishConnection() verifying User Directed Commissioning (UDC) state");
+ mIdOptions.LogDetail();
+ SuccessOrExit(err = support::ChipDeviceEventHandler::SetUdcStatus(true));
+
+ if (!GetSupportsCommissionerGeneratedPasscode() && mIdOptions.mCommissionerPasscode)
+ {
+ ChipLogError(
+ AppServer,
+ "CastingPlayer::VerifyOrEstablishConnection() the target CastingPlayer doesn't support Commissioner-Generated "
+ "passcode yet IdentificationDeclarationOptions.mCommissionerPasscode is set to true");
+ SuccessOrExit(err = CHIP_ERROR_INVALID_ARGUMENT);
+ }
+ if (!matter::casting::core::CommissionerDeclarationHandler::GetInstance()->HasCommissionerDeclarationCallback() &&
+ mIdOptions.mCommissionerPasscode)
+ {
+ ChipLogError(AppServer,
+ "CastingPlayer::VerifyOrEstablishConnection() the CommissionerDeclaration message callback has not been "
+ "set yet IdentificationDeclarationOptions.mCommissionerPasscode is set to true");
+ SuccessOrExit(err = CHIP_ERROR_INVALID_ARGUMENT);
+ }
+
+ ChipLogProgress(AppServer, "CastingPlayer::VerifyOrEstablishConnection() calling OpenBasicCommissioningWindow()");
SuccessOrExit(err = chip::Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow(
chip::System::Clock::Seconds16(mCommissioningWindowTimeoutSec)));
+ ChipLogProgress(AppServer, "CastingPlayer::VerifyOrEstablishConnection() calling SendUserDirectedCommissioningRequest()");
#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
SuccessOrExit(err = SendUserDirectedCommissioningRequest());
#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
@@ -130,10 +174,65 @@
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "CastingPlayer::VerifyOrEstablishConnection() failed with %" CHIP_ERROR_FORMAT, err.Format());
- support::ChipDeviceEventHandler::SetUdcStatus(false);
- mConnectionState = CASTING_PLAYER_NOT_CONNECTED;
- mCommissioningWindowTimeoutSec = kCommissioningWindowTimeoutSec;
- mTargetCastingPlayer = nullptr;
+ resetState(err);
+ }
+}
+
+void CastingPlayer::ContinueConnecting(ConnectionCallbacks connectionCallbacks,
+ unsigned long long int commissioningWindowTimeoutSec)
+{
+ ChipLogProgress(AppServer, "CastingPlayer::ContinueConnecting()");
+ CHIP_ERROR err = CHIP_NO_ERROR;
+ SuccessOrExit(err = support::ChipDeviceEventHandler::SetUdcStatus(true));
+ VerifyOrExit(
+ connectionCallbacks.mOnConnectionComplete != nullptr,
+ ChipLogError(AppServer, "CastingPlayer::ContinueConnecting() ConnectionCallbacks.mOnConnectionComplete was not provided"));
+ mConnectionState = CASTING_PLAYER_CONNECTING;
+ mOnCompleted = connectionCallbacks.mOnConnectionComplete;
+ mCommissioningWindowTimeoutSec = commissioningWindowTimeoutSec;
+ mTargetCastingPlayer = this;
+
+ // Register the handler for Commissioner's CommissionerDeclaration messages. The CommissionerDeclaration messages provide
+ // information indicating the Commissioner's pre-commissioning state.
+ if (connectionCallbacks.mCommissionerDeclarationCallback != nullptr)
+ {
+ matter::casting::core::CommissionerDeclarationHandler::GetInstance()->SetCommissionerDeclarationCallback(
+ connectionCallbacks.mCommissionerDeclarationCallback);
+ }
+ else
+ {
+ ChipLogProgress(
+ AppServer,
+ "CastingPlayer::VerifyOrEstablishConnection() CommissionerDeclarationCallback not provided in ConnectionCallbacks");
+ }
+
+ ChipLogProgress(AppServer, "CastingPlayer::ContinueConnecting() calling OpenBasicCommissioningWindow()");
+ SuccessOrExit(err = chip::Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow(
+ chip::System::Clock::Seconds16(mCommissioningWindowTimeoutSec)));
+
+ mIdOptions.mCommissionerPasscodeReady = true;
+ ChipLogProgress(AppServer, "CastingPlayer::ContinueConnecting() calling SendUserDirectedCommissioningRequest()");
+#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
+ SuccessOrExit(err = SendUserDirectedCommissioningRequest());
+#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
+
+exit:
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogError(AppServer, "CastingPlayer::ContinueConnecting() failed with %" CHIP_ERROR_FORMAT, err.Format());
+ resetState(err);
+ }
+}
+
+void CastingPlayer::resetState(CHIP_ERROR err)
+{
+ ChipLogProgress(AppServer, "CastingPlayer::resetState()");
+ support::ChipDeviceEventHandler::SetUdcStatus(false);
+ mConnectionState = CASTING_PLAYER_NOT_CONNECTED;
+ mCommissioningWindowTimeoutSec = kCommissioningWindowTimeoutSec;
+ mTargetCastingPlayer = nullptr;
+ if (mOnCompleted)
+ {
mOnCompleted(err, nullptr);
mOnCompleted = nullptr;
}
@@ -171,8 +270,6 @@
VerifyOrReturnValue(ipAddressToUse != nullptr, CHIP_ERROR_INCORRECT_STATE,
ChipLogError(AppServer, "No IP Address found to send UDC request to"));
- ReturnErrorOnFailure(support::ChipDeviceEventHandler::SetUdcStatus(true));
-
chip::Protocols::UserDirectedCommissioning::IdentificationDeclaration id = mIdOptions.buildIdentificationDeclarationMessage();
ReturnErrorOnFailure(chip::Server::GetInstance().SendUserDirectedCommissioningRequest(
@@ -246,7 +343,7 @@
void CastingPlayer::LogDetail() const
{
- ChipLogProgress(AppServer, "CastingPlayer::LogDetail() called");
+ ChipLogProgress(AppServer, "CastingPlayer::LogDetail()");
if (strlen(mAttributes.id) != 0)
{
ChipLogDetail(AppServer, "\tID: %s", mAttributes.id);
@@ -308,6 +405,7 @@
chip::OnDeviceConnected onDeviceConnectedFn,
chip::OnDeviceConnectionFailure onDeviceConnectionFailureFn)
{
+ ChipLogProgress(AppServer, "CastingPlayer::ConnectionContext()");
mClientContext = clientContext;
mTargetCastingPlayer = targetCastingPlayer;
mOnDeviceConnectedFn = onDeviceConnectedFn;
diff --git a/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h b/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h
index 2748eaf..14a55e0 100644
--- a/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h
+++ b/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h
@@ -19,6 +19,7 @@
#pragma once
#include "CommissionerDeclarationHandler.h"
+#include "ConnectionCallbacks.h"
#include "Endpoint.h"
#include "IdentificationDeclarationOptions.h"
#include "Types.h"
@@ -86,7 +87,6 @@
class ConnectionContext;
class CastingPlayer;
-using ConnectCallback = std::function<void(CHIP_ERROR, CastingPlayer *)>;
/**
* @brief CastingPlayer represents a Matter commissioner that is able to play media to a physical
@@ -119,23 +119,40 @@
/**
* @brief Verifies that a connection exists with this CastingPlayer, or triggers a new session
* request. If the CastingApp does not have the nodeId and fabricIndex of this CastingPlayer cached on disk,
- * this will execute the user directed commissioning process.
+ * this will execute the User Directed Commissioning (UDC) process.
*
- * @param onCompleted for success - called back with CHIP_NO_ERROR and CastingPlayer *.
- * For failure - called back with an error and nullptr.
+ * @param connectionCallbacks contains the ConnectCallback and CommissionerDeclarationCallback (Optional).
* @param commissioningWindowTimeoutSec (Optional) time (in sec) to keep the commissioning window open, if commissioning is
* required. Needs to be >= kCommissioningWindowTimeoutSec.
* @param idOptions (Optional) Parameters in the IdentificationDeclaration message sent by the Commissionee to the Commissioner.
* These parameters specify the information relating to the requested commissioning session.
* Furthermore, attributes (such as VendorId) describe the TargetApp that the client wants to interact with after commissioning.
- * If this value is passed in, VerifyOrEstablishConnection() will force User Directed Commissioning, in case the desired
+ * If this value is passed in, VerifyOrEstablishConnection() will force UDC, in case the desired
* TargetApp is not found in the on-device CastingStore.
*/
- void VerifyOrEstablishConnection(ConnectCallback onCompleted,
+ void VerifyOrEstablishConnection(ConnectionCallbacks connectionCallbacks,
unsigned long long int commissioningWindowTimeoutSec = kCommissioningWindowTimeoutSec,
IdentificationDeclarationOptions idOptions = IdentificationDeclarationOptions());
/**
+ * @brief Continues the UDC process during the Commissioner-Generated passcode commissioning flow by sending a second
+ * IdentificationDeclaration to Commissioner containing CommissionerPasscode and CommissionerPasscodeReady set to true. At this
+ * point it is assumed that the following have occurred:
+ * 1. Client has handled the Commissioner's CommissionerDecelration message with PasscodeDialogDisplayed and
+ * CommissionerPasscode set to true.
+ * 2. Client prompted user to input Passcode from Commissioner.
+ * 3. Client has updated the commissioning session's PAKE verifier using the user input Passcode by updating the CastingApps
+ * CommissionableDataProvider
+ * (matter::casting::core::CastingApp::GetInstance()->UpdateCommissionableDataProvider(CommissionableDataProvider)).
+ *
+ * @param connectionCallbacks contains the ConnectCallback and CommissionerDeclarationCallback (Optional).
+ * @param commissioningWindowTimeoutSec (Optional) time (in sec) to keep the commissioning window open, if commissioning is
+ * required. Needs to be >= kCommissioningWindowTimeoutSec.
+ */
+ void ContinueConnecting(ConnectionCallbacks connectionCallbacks,
+ unsigned long long int commissioningWindowTimeoutSec = kCommissioningWindowTimeoutSec);
+
+ /**
* @brief Sets the internal connection state of this CastingPlayer to "disconnected"
*/
void Disconnect();
@@ -206,6 +223,12 @@
unsigned long long int mCommissioningWindowTimeoutSec = kCommissioningWindowTimeoutSec;
ConnectCallback mOnCompleted = {};
+ /**
+ * @brief resets this CastingPlayer's state and calls mOnCompleted with the CHIP_ERROR. Also, after calling mOnCompleted, it
+ * clears mOnCompleted by setting it to a nullptr.
+ */
+ void resetState(CHIP_ERROR err);
+
#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
/**
* @brief Sends the user directed commissioning request to this CastingPlayer
diff --git a/examples/tv-casting-app/tv-casting-common/core/CommissionerDeclarationHandler.cpp b/examples/tv-casting-app/tv-casting-common/core/CommissionerDeclarationHandler.cpp
index 1bedc6c..bb9ecc3 100644
--- a/examples/tv-casting-app/tv-casting-common/core/CommissionerDeclarationHandler.cpp
+++ b/examples/tv-casting-app/tv-casting-common/core/CommissionerDeclarationHandler.cpp
@@ -19,6 +19,8 @@
#include "CommissionerDeclarationHandler.h"
#include "Types.h"
+#include "support/ChipDeviceEventHandler.h"
+#include <app/server/Server.h>
namespace matter {
namespace casting {
@@ -36,14 +38,36 @@
}
// TODO: In the following PRs. Implement setHandler() for CommissionerDeclaration messages and expose messages to higher layers for
-// Linux, Android and iOS.
+// Linux(DONE), Android(pending) and iOS(pending).
void CommissionerDeclarationHandler::OnCommissionerDeclarationMessage(
const chip::Transport::PeerAddress & source, chip::Protocols::UserDirectedCommissioning::CommissionerDeclaration cd)
{
- ChipLogProgress(AppServer, "CommissionerDeclarationHandler::OnCommissionerDeclarationMessage() called TODO: handle message");
- cd.DebugLog();
+ ChipLogProgress(AppServer,
+ "CommissionerDeclarationHandler::OnCommissionerDeclarationMessage(), calling CloseCommissioningWindow()");
+ // Close the commissioning window. Since we recived a CommissionerDeclaration message from the Commissioner, we know that
+ // commissioning via AccountLogin cluster failed. We will open a new commissioningWindow prior to sending the next
+ // IdentificationDeclaration Message to the Commissioner.
+ chip::Server::GetInstance().GetCommissioningWindowManager().CloseCommissioningWindow();
+ support::ChipDeviceEventHandler::SetUdcStatus(false);
+
+ if (mCmmissionerDeclarationCallback_)
+ {
+ mCmmissionerDeclarationCallback_(source, cd);
+ }
+ else
+ {
+ ChipLogError(AppServer,
+ "CommissionerDeclarationHandler::OnCommissionerDeclarationMessage() mCmmissionerDeclarationCallback_ not set");
+ }
}
-}; // namespace core
-}; // namespace casting
-}; // namespace matter
+void CommissionerDeclarationHandler::SetCommissionerDeclarationCallback(
+ matter::casting::core::CommissionerDeclarationCallback callback)
+{
+ ChipLogProgress(AppServer, "CommissionerDeclarationHandler::SetCommissionerDeclarationCallback()");
+ mCmmissionerDeclarationCallback_ = std::move(callback);
+}
+
+} // namespace core
+} // namespace casting
+} // namespace matter
diff --git a/examples/tv-casting-app/tv-casting-common/core/CommissionerDeclarationHandler.h b/examples/tv-casting-app/tv-casting-common/core/CommissionerDeclarationHandler.h
index e84ca59..ac41892 100644
--- a/examples/tv-casting-app/tv-casting-common/core/CommissionerDeclarationHandler.h
+++ b/examples/tv-casting-app/tv-casting-common/core/CommissionerDeclarationHandler.h
@@ -18,6 +18,7 @@
#pragma once
+#include "ConnectionCallbacks.h"
#include "Types.h"
namespace matter {
@@ -25,7 +26,8 @@
namespace core {
/**
- * @brief React to the Commissioner's CommissionerDeclaration messages with this singleton.
+ * @brief React to the Commissioner's CommissionerDeclaration messages with this singleton. This is an implementation of the
+ * CommissionerDeclarationHandler from connectedhomeip/src/protocols/user_directed_commissioning/UserDirectedCommissioning.h.
*/
class CommissionerDeclarationHandler : public chip::Protocols::UserDirectedCommissioning::CommissionerDeclarationHandler
{
@@ -35,15 +37,33 @@
static CommissionerDeclarationHandler * GetInstance();
+ /**
+ * @brief Called when a Commissioner Declaration UDC message has been received.
+ * @param[in] source The source of the Commissioner Declaration message.
+ * @param[in] cd The Commissioner Declaration message.
+ */
void OnCommissionerDeclarationMessage(const chip::Transport::PeerAddress & source,
chip::Protocols::UserDirectedCommissioning::CommissionerDeclaration cd) override;
+ /**
+ * @brief OnCommissionerDeclarationMessage() will call the CommissionerDeclarationCallback set by this function.
+ */
+ void SetCommissionerDeclarationCallback(CommissionerDeclarationCallback callback);
+
+ /**
+ * @brief returns true if the CommissionerDeclarationHandler sigleton has a CommissionerDeclarationCallback set, false
+ * otherwise.
+ */
+ bool HasCommissionerDeclarationCallback() { return static_cast<bool>(mCmmissionerDeclarationCallback_); };
+
private:
static CommissionerDeclarationHandler * sCommissionerDeclarationHandler_;
+ CommissionerDeclarationCallback mCmmissionerDeclarationCallback_;
+
CommissionerDeclarationHandler() {}
~CommissionerDeclarationHandler() {}
};
-}; // namespace core
-}; // namespace casting
-}; // namespace matter
+} // namespace core
+} // namespace casting
+} // namespace matter
diff --git a/examples/tv-casting-app/tv-casting-common/core/ConnectionCallbacks.h b/examples/tv-casting-app/tv-casting-common/core/ConnectionCallbacks.h
new file mode 100644
index 0000000..01badaa
--- /dev/null
+++ b/examples/tv-casting-app/tv-casting-common/core/ConnectionCallbacks.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * 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 "Types.h"
+
+namespace matter {
+namespace casting {
+namespace core {
+
+class CastingPlayer;
+
+/**
+ * @brief Called when the User Directed Commissioning (UDC) process succeeds or fails.
+ * @param[in] err For success, called back with CHIP_NO_ERROR. For failure, called back with an error.
+ * @param[in] castingPlayer For success, called back with a CastingPlayer *. For failure, called back with a nullptr.
+ */
+using ConnectCallback = std::function<void(CHIP_ERROR err, CastingPlayer * castingPlayer)>;
+
+/**
+ * @brief Called when a Commissioner Declaration UDC message has been received.
+ * @param[in] source The source of the Commissioner Declaration message.
+ * @param[in] cd The Commissioner Declaration message.
+ */
+using CommissionerDeclarationCallback = std::function<void(
+ const chip::Transport::PeerAddress & source, const chip::Protocols::UserDirectedCommissioning::CommissionerDeclaration cd)>;
+
+/**
+ * @brief A container struct for User Directed Commissioning (UDC) callbacks.
+ */
+struct ConnectionCallbacks
+{
+ /**
+ * The callback called when the connection process has ended, regardless of whether it was successful or not.
+ */
+ ConnectCallback mOnConnectionComplete = nullptr;
+ /**
+ * The callback called when the Commissionee receives a CommissionerDeclaration message from the Commissioner.
+ */
+ CommissionerDeclarationCallback mCommissionerDeclarationCallback = nullptr;
+};
+
+} // namespace core
+} // namespace casting
+} // namespace matter
diff --git a/examples/tv-casting-app/tv-casting-common/core/IdentificationDeclarationOptions.h b/examples/tv-casting-app/tv-casting-common/core/IdentificationDeclarationOptions.h
index af1ae2a..d0e8f8a 100644
--- a/examples/tv-casting-app/tv-casting-common/core/IdentificationDeclarationOptions.h
+++ b/examples/tv-casting-app/tv-casting-common/core/IdentificationDeclarationOptions.h
@@ -19,6 +19,7 @@
#pragma once
#include "Types.h"
+#include <app/server/Dnssd.h>
#include <vector>
namespace matter {
@@ -61,8 +62,15 @@
*/
bool mCancelPasscode = false;
+ /**
+ * Commissionee's (random) DNS-SD instance name. This field is mandatory and will be auto generated if not provided by the
+ * client.
+ */
+ char mCommissioneeInstanceName[chip::Dnssd::Commission::kInstanceNameMaxLength + 1] = "";
+
CHIP_ERROR addTargetAppInfo(const chip::Protocols::UserDirectedCommissioning::TargetAppInfo & targetAppInfo)
{
+ ChipLogProgress(AppServer, "IdentificationDeclarationOptions::addTargetAppInfo()");
if (mTargetAppInfos.size() >= CHIP_DEVICE_CONFIG_UDC_MAX_TARGET_APPS)
{
ChipLogError(AppServer,
@@ -94,23 +102,54 @@
id.SetNoPasscode(mNoPasscode);
id.SetCdUponPasscodeDialog(mCdUponPasscodeDialog);
id.SetCancelPasscode(mCancelPasscode);
-
- ChipLogProgress(AppServer,
- "IdentificationDeclarationOptions::buildIdentificationDeclarationMessage() mCommissionerPasscode: %s",
- mCommissionerPasscode ? "true" : "false");
id.SetCommissionerPasscode(mCommissionerPasscode);
-
- ChipLogProgress(AppServer,
- "IdentificationDeclarationOptions::buildIdentificationDeclarationMessage() mCommissionerPasscodeReady: %s",
- mCommissionerPasscodeReady ? "true" : "false");
if (mCommissionerPasscodeReady)
{
id.SetCommissionerPasscodeReady(true);
+ id.SetInstanceName(mCommissioneeInstanceName);
mCommissionerPasscodeReady = false;
}
+ else
+ {
+ ChipLogProgress(AppServer,
+ "IdentificationDeclarationOptions::buildIdentificationDeclarationMessage() generating InstanceName");
+ CHIP_ERROR err = chip::app::DnssdServer::Instance().GetCommissionableInstanceName(mCommissioneeInstanceName,
+ sizeof(mCommissioneeInstanceName));
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogError(AppServer,
+ "IdentificationDeclarationOptions::buildIdentificationDeclarationMessage() Failed to get mdns "
+ "instance name error: %" CHIP_ERROR_FORMAT,
+ err.Format());
+ }
+ else
+ {
+ id.SetInstanceName(mCommissioneeInstanceName);
+ ChipLogProgress(AppServer,
+ "IdentificationDeclarationOptions::buildIdentificationDeclarationMessage() InstanceName set to: %s",
+ mCommissioneeInstanceName);
+ }
+ }
+ LogDetail();
return id;
}
+ void LogDetail()
+ {
+ ChipLogDetail(AppServer, "IdentificationDeclarationOptions::LogDetail()");
+ ChipLogDetail(AppServer, "IdentificationDeclarationOptions::mNoPasscode: %s",
+ mNoPasscode ? "true" : "false");
+ ChipLogDetail(AppServer, "IdentificationDeclarationOptions::mCdUponPasscodeDialog: %s",
+ mCdUponPasscodeDialog ? "true" : "false");
+ ChipLogDetail(AppServer, "IdentificationDeclarationOptions::mCommissionerPasscode: %s",
+ mCommissionerPasscode ? "true" : "false");
+ ChipLogDetail(AppServer, "IdentificationDeclarationOptions::mCommissionerPasscodeReady: %s",
+ mCommissionerPasscodeReady ? "true" : "false");
+ ChipLogDetail(AppServer, "IdentificationDeclarationOptions::mCancelPasscode: %s",
+ mCancelPasscode ? "true" : "false");
+ ChipLogDetail(AppServer, "IdentificationDeclarationOptions::mCommissioneeInstanceName: %s", mCommissioneeInstanceName);
+ }
+
private:
/**
* Feature: Target Content Application
diff --git a/examples/tv-casting-app/tv-casting-common/support/AppParameters.h b/examples/tv-casting-app/tv-casting-common/support/AppParameters.h
index 080011f..e48a45e 100644
--- a/examples/tv-casting-app/tv-casting-common/support/AppParameters.h
+++ b/examples/tv-casting-app/tv-casting-common/support/AppParameters.h
@@ -42,7 +42,6 @@
chip::Credentials::DeviceAttestationCredentialsProvider * deviceAttestationCredentialsProvider,
chip::Credentials::DeviceAttestationVerifier * deviceAttestationVerifier,
ServerInitParamsProvider * serverInitParamsProvider)
- // TODO: In the following PRs. Add CommissionerDeclarationHandler.
{
VerifyOrReturnError(commissionableDataProvider != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(deviceAttestationCredentialsProvider != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
@@ -62,6 +61,14 @@
chip::DeviceLayer::CommissionableDataProvider * GetCommissionableDataProvider() const { return mCommissionableDataProvider; }
+ CHIP_ERROR SetCommissionableDataProvider(chip::DeviceLayer::CommissionableDataProvider * commissionableDataProvider) const
+ {
+ ChipLogProgress(AppServer, "AppParameters::SetCommissionableDataProvider()");
+ VerifyOrReturnError(commissionableDataProvider != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
+ mCommissionableDataProvider = commissionableDataProvider;
+ return CHIP_NO_ERROR;
+ }
+
chip::Credentials::DeviceAttestationCredentialsProvider * GetDeviceAttestationCredentialsProvider() const
{
return mDeviceAttestationCredentialsProvider;
@@ -82,7 +89,7 @@
* @brief Provides CommissionableData (such as setupPasscode, discriminator, etc) used to get the CastingApp commissioned
*
*/
- chip::DeviceLayer::CommissionableDataProvider * mCommissionableDataProvider;
+ mutable chip::DeviceLayer::CommissionableDataProvider * mCommissionableDataProvider;
/**
* @brief Provides DeviceAttestationCredentials of the CastingApp during commissioning
diff --git a/examples/tv-casting-app/tv-casting-common/support/ChipDeviceEventHandler.cpp b/examples/tv-casting-app/tv-casting-common/support/ChipDeviceEventHandler.cpp
index bddc64f..fd6039d 100644
--- a/examples/tv-casting-app/tv-casting-common/support/ChipDeviceEventHandler.cpp
+++ b/examples/tv-casting-app/tv-casting-common/support/ChipDeviceEventHandler.cpp
@@ -94,7 +94,7 @@
// if UDC was in progress (when the Fail-Safe timer expired), reset TargetCastingPlayer commissioning state and return early
if (sUdcInProgress)
{
- ChipLogProgress(AppServer, "ChipDeviceEventHandler::HandleFailSafeTimerExpired when sUdcInProgress: %d, returning early",
+ ChipLogProgress(AppServer, "ChipDeviceEventHandler::HandleFailSafeTimerExpired() when sUdcInProgress: %d, returning early",
sUdcInProgress);
sUdcInProgress = false;
CastingPlayer::GetTargetCastingPlayer()->mConnectionState = CASTING_PLAYER_NOT_CONNECTED;
@@ -105,17 +105,19 @@
}
// if UDC was NOT in progress (when the Fail-Safe timer expired), start UDC
- ChipLogProgress(AppServer, "ChipDeviceEventHandler::HandleFailSafeTimerExpired when sUdcInProgress: %d, starting UDC",
+ ChipLogProgress(AppServer, "ChipDeviceEventHandler::HandleFailSafeTimerExpired() when sUdcInProgress: %d, starting UDC",
sUdcInProgress);
chip::DeviceLayer::SystemLayer().StartTimer(
chip::System::Clock::Milliseconds32(1),
[](chip::System::Layer * aSystemLayer, void * aAppState) {
- ChipLogProgress(AppServer, "ChipDeviceEventHandler::Handle running OpenBasicCommissioningWindow");
+ ChipLogProgress(AppServer, "ChipDeviceEventHandler::HandleFailSafeTimerExpired() running OpenBasicCommissioningWindow");
CHIP_ERROR err = chip::Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow(
chip::System::Clock::Seconds16(CastingPlayer::GetTargetCastingPlayer()->mCommissioningWindowTimeoutSec));
if (err != CHIP_NO_ERROR)
{
- ChipLogError(AppServer, "ChipDeviceEventHandler::Handle Failed to OpenBasicCommissioningWindow %" CHIP_ERROR_FORMAT,
+ ChipLogError(AppServer,
+ "ChipDeviceEventHandler::HandleFailSafeTimerExpired() Failed to OpenBasicCommissioningWindow "
+ "%" CHIP_ERROR_FORMAT,
err.Format());
CastingPlayer::GetTargetCastingPlayer()->mOnCompleted(err, nullptr);
return;
@@ -126,7 +128,8 @@
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer,
- "ChipDeviceEventHandler::Handle Failed to SendUserDirectedCommissioningRequest %" CHIP_ERROR_FORMAT,
+ "ChipDeviceEventHandler::HandleFailSafeTimerExpired() Failed to SendUserDirectedCommissioningRequest "
+ "%" CHIP_ERROR_FORMAT,
err.Format());
CastingPlayer::GetTargetCastingPlayer()->mOnCompleted(err, nullptr);
return;
@@ -209,10 +212,10 @@
CHIP_ERROR ChipDeviceEventHandler::SetUdcStatus(bool udcInProgress)
{
- ChipLogProgress(AppServer, "ChipDeviceEventHandler::SetUdcStatus called with udcInProgress: %d", udcInProgress);
+ ChipLogProgress(AppServer, "ChipDeviceEventHandler::SetUdcStatus() called with udcInProgress: %d", udcInProgress);
if (sUdcInProgress == udcInProgress)
{
- ChipLogError(AppServer, "UDC in progress state is already %d", sUdcInProgress);
+ ChipLogError(AppServer, "ChipDeviceEventHandler::SetUdcStatus() UDC in progress state is already %d", sUdcInProgress);
return CHIP_ERROR_INCORRECT_STATE;
}
sUdcInProgress = udcInProgress;
diff --git a/src/app/server/Server.cpp b/src/app/server/Server.cpp
index ad085d5..7a91dec 100644
--- a/src/app/server/Server.cpp
+++ b/src/app/server/Server.cpp
@@ -628,23 +628,27 @@
// only populate fields left blank by the client
if (strlen(id.GetInstanceName()) == 0)
{
+ ChipLogDetail(AppServer, "Server::SendUserDirectedCommissioningRequest() Instance Name not known");
char nameBuffer[chip::Dnssd::Commission::kInstanceNameMaxLength + 1];
err = app::DnssdServer::Instance().GetCommissionableInstanceName(nameBuffer, sizeof(nameBuffer));
if (err != CHIP_NO_ERROR)
{
- ChipLogError(AppServer, "Failed to get mdns instance name error: %" CHIP_ERROR_FORMAT, err.Format());
+ ChipLogError(
+ AppServer,
+ "Server::SendUserDirectedCommissioningRequest() Failed to get mdns instance name error: %" CHIP_ERROR_FORMAT,
+ err.Format());
return err;
}
id.SetInstanceName(nameBuffer);
+ ChipLogDetail(AppServer, "Server::SendUserDirectedCommissioningRequest() Instance Name set to %s", nameBuffer);
}
- ChipLogDetail(AppServer, "instanceName=%s", id.GetInstanceName());
if (id.GetVendorId() == 0)
{
uint16_t vendorId = 0;
if (DeviceLayer::GetDeviceInstanceInfoProvider()->GetVendorId(vendorId) != CHIP_NO_ERROR)
{
- ChipLogDetail(Discovery, "Vendor ID not known");
+ ChipLogDetail(AppServer, "Server::SendUserDirectedCommissioningRequest() Vendor ID not known");
}
else
{
@@ -657,7 +661,7 @@
uint16_t productId = 0;
if (DeviceLayer::GetDeviceInstanceInfoProvider()->GetProductId(productId) != CHIP_NO_ERROR)
{
- ChipLogDetail(Discovery, "Product ID not known");
+ ChipLogDetail(AppServer, "Server::SendUserDirectedCommissioningRequest() Product ID not known");
}
else
{
@@ -671,7 +675,7 @@
if (!chip::DeviceLayer::ConfigurationMgr().IsCommissionableDeviceNameEnabled() ||
chip::DeviceLayer::ConfigurationMgr().GetCommissionableDeviceName(deviceName, sizeof(deviceName)) != CHIP_NO_ERROR)
{
- ChipLogDetail(Discovery, "Device Name not known");
+ ChipLogDetail(AppServer, "Server::SendUserDirectedCommissioningRequest() Device Name not known");
}
else
{
@@ -710,11 +714,12 @@
if (err == CHIP_NO_ERROR)
{
- ChipLogDetail(AppServer, "Send UDC request success");
+ ChipLogDetail(AppServer, "Server::SendUserDirectedCommissioningRequest() Send UDC request success");
}
else
{
- ChipLogError(AppServer, "Send UDC request failed, err: %" CHIP_ERROR_FORMAT, err.Format());
+ ChipLogError(AppServer, "Server::SendUserDirectedCommissioningRequest() Send UDC request failed, err: %" CHIP_ERROR_FORMAT,
+ err.Format());
}
return err;
}