CHIPCommand.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. /*
  2. * Copyright (c) 2021-2022 Project CHIP Authors
  3. * All rights reserved.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #include "CHIPCommand.h"
  19. #include <controller/CHIPDeviceControllerFactory.h>
  20. #include <core/CHIPBuildConfig.h>
  21. #include <credentials/attestation_verifier/FileAttestationTrustStore.h>
  22. #include <lib/core/CHIPVendorIdentifiers.hpp>
  23. #include <lib/support/CodeUtils.h>
  24. #include <lib/support/ScopedBuffer.h>
  25. #include <lib/support/TestGroupData.h>
  26. #include <platform/LockTracker.h>
  27. #if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
  28. #include "TraceDecoder.h"
  29. #include "TraceHandlers.h"
  30. #endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
  31. std::map<CHIPCommand::CommissionerIdentity, std::unique_ptr<chip::Controller::DeviceCommissioner>> CHIPCommand::mCommissioners;
  32. std::set<CHIPCommand *> CHIPCommand::sDeferredCleanups;
  33. using DeviceControllerFactory = chip::Controller::DeviceControllerFactory;
  34. constexpr chip::FabricId kIdentityNullFabricId = chip::kUndefinedFabricId;
  35. constexpr chip::FabricId kIdentityAlphaFabricId = 1;
  36. constexpr chip::FabricId kIdentityBetaFabricId = 2;
  37. constexpr chip::FabricId kIdentityGammaFabricId = 3;
  38. constexpr chip::FabricId kIdentityOtherFabricId = 4;
  39. constexpr const char * kPAATrustStorePathVariable = "CHIPTOOL_PAA_TRUST_STORE_PATH";
  40. constexpr const char * kCDTrustStorePathVariable = "CHIPTOOL_CD_TRUST_STORE_PATH";
  41. const chip::Credentials::AttestationTrustStore * CHIPCommand::sTrustStore = nullptr;
  42. chip::Credentials::GroupDataProviderImpl CHIPCommand::sGroupDataProvider{ kMaxGroupsPerFabric, kMaxGroupKeysPerFabric };
  43. namespace {
  44. CHIP_ERROR GetAttestationTrustStore(const char * paaTrustStorePath, const chip::Credentials::AttestationTrustStore ** trustStore)
  45. {
  46. if (paaTrustStorePath == nullptr)
  47. {
  48. paaTrustStorePath = getenv(kPAATrustStorePathVariable);
  49. }
  50. if (paaTrustStorePath == nullptr)
  51. {
  52. *trustStore = chip::Credentials::GetTestAttestationTrustStore();
  53. return CHIP_NO_ERROR;
  54. }
  55. static chip::Credentials::FileAttestationTrustStore attestationTrustStore{ paaTrustStorePath };
  56. if (paaTrustStorePath != nullptr && attestationTrustStore.paaCount() == 0)
  57. {
  58. ChipLogError(chipTool, "No PAAs found in path: %s", paaTrustStorePath);
  59. ChipLogError(chipTool,
  60. "Please specify a valid path containing trusted PAA certificates using "
  61. "the argument [--paa-trust-store-path paa/file/path] "
  62. "or environment variable [%s=paa/file/path]",
  63. kPAATrustStorePathVariable);
  64. return CHIP_ERROR_INVALID_ARGUMENT;
  65. }
  66. *trustStore = &attestationTrustStore;
  67. return CHIP_NO_ERROR;
  68. }
  69. } // namespace
  70. CHIP_ERROR CHIPCommand::MaybeSetUpStack()
  71. {
  72. if (IsInteractive())
  73. {
  74. return CHIP_NO_ERROR;
  75. }
  76. StartTracing();
  77. #if (CHIP_DEVICE_LAYER_TARGET_LINUX || CHIP_DEVICE_LAYER_TARGET_TIZEN) && CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
  78. // By default, Linux device is configured as a BLE peripheral while the controller needs a BLE central.
  79. ReturnLogErrorOnFailure(chip::DeviceLayer::Internal::BLEMgrImpl().ConfigureBle(mBleAdapterId.ValueOr(0), true));
  80. #endif
  81. ReturnLogErrorOnFailure(mDefaultStorage.Init(nullptr, GetStorageDirectory().ValueOr(nullptr)));
  82. ReturnLogErrorOnFailure(mOperationalKeystore.Init(&mDefaultStorage));
  83. ReturnLogErrorOnFailure(mOpCertStore.Init(&mDefaultStorage));
  84. chip::Controller::FactoryInitParams factoryInitParams;
  85. factoryInitParams.fabricIndependentStorage = &mDefaultStorage;
  86. factoryInitParams.operationalKeystore = &mOperationalKeystore;
  87. factoryInitParams.opCertStore = &mOpCertStore;
  88. factoryInitParams.enableServerInteractions = NeedsOperationalAdvertising();
  89. factoryInitParams.sessionKeystore = &mSessionKeystore;
  90. // Init group data provider that will be used for all group keys and IPKs for the
  91. // chip-tool-configured fabrics. This is OK to do once since the fabric tables
  92. // and the DeviceControllerFactory all "share" in the same underlying data.
  93. // Different commissioner implementations may want to use alternate implementations
  94. // of GroupDataProvider for injection through factoryInitParams.
  95. sGroupDataProvider.SetStorageDelegate(&mDefaultStorage);
  96. sGroupDataProvider.SetSessionKeystore(factoryInitParams.sessionKeystore);
  97. ReturnLogErrorOnFailure(sGroupDataProvider.Init());
  98. chip::Credentials::SetGroupDataProvider(&sGroupDataProvider);
  99. factoryInitParams.groupDataProvider = &sGroupDataProvider;
  100. uint16_t port = mDefaultStorage.GetListenPort();
  101. if (port != 0)
  102. {
  103. // Make sure different commissioners run on different ports.
  104. port = static_cast<uint16_t>(port + CurrentCommissionerId());
  105. }
  106. factoryInitParams.listenPort = port;
  107. ReturnLogErrorOnFailure(DeviceControllerFactory::GetInstance().Init(factoryInitParams));
  108. ReturnErrorOnFailure(GetAttestationTrustStore(mPaaTrustStorePath.ValueOr(nullptr), &sTrustStore));
  109. CommissionerIdentity nullIdentity{ kIdentityNull, chip::kUndefinedNodeId };
  110. ReturnLogErrorOnFailure(InitializeCommissioner(nullIdentity, kIdentityNullFabricId));
  111. // After initializing first commissioner, add the additional CD certs once
  112. {
  113. const char * cdTrustStorePath = mCDTrustStorePath.ValueOr(nullptr);
  114. if (cdTrustStorePath == nullptr)
  115. {
  116. cdTrustStorePath = getenv(kCDTrustStorePathVariable);
  117. }
  118. auto additionalCdCerts = chip::Credentials::LoadAllX509DerCerts(cdTrustStorePath);
  119. if (cdTrustStorePath != nullptr && additionalCdCerts.size() == 0)
  120. {
  121. ChipLogError(chipTool, "Warning: no CD signing certs found in path: %s, only defaults will be used", cdTrustStorePath);
  122. ChipLogError(chipTool,
  123. "Please specify a path containing trusted CD verifying key certificates using "
  124. "the argument [--cd-trust-store-path cd/file/path] "
  125. "or environment variable [%s=cd/file/path]",
  126. kCDTrustStorePathVariable);
  127. }
  128. ReturnErrorOnFailure(mCredIssuerCmds->AddAdditionalCDVerifyingCerts(additionalCdCerts));
  129. }
  130. bool allowTestCdSigningKey = !mOnlyAllowTrustedCdKeys.ValueOr(false);
  131. mCredIssuerCmds->SetCredentialIssuerOption(CredentialIssuerCommands::CredentialIssuerOptions::kAllowTestCdSigningKey,
  132. allowTestCdSigningKey);
  133. return CHIP_NO_ERROR;
  134. }
  135. void CHIPCommand::MaybeTearDownStack()
  136. {
  137. if (IsInteractive())
  138. {
  139. return;
  140. }
  141. //
  142. // We can call DeviceController::Shutdown() safely without grabbing the stack lock
  143. // since the CHIP thread and event queue have been stopped, preventing any thread
  144. // races.
  145. //
  146. for (auto & commissioner : mCommissioners)
  147. {
  148. ShutdownCommissioner(commissioner.first);
  149. }
  150. StopTracing();
  151. }
  152. CHIP_ERROR CHIPCommand::EnsureCommissionerForIdentity(std::string identity)
  153. {
  154. chip::NodeId nodeId;
  155. ReturnErrorOnFailure(GetIdentityNodeId(identity, &nodeId));
  156. CommissionerIdentity lookupKey{ identity, nodeId };
  157. if (mCommissioners.find(lookupKey) != mCommissioners.end())
  158. {
  159. return CHIP_NO_ERROR;
  160. }
  161. // Need to initialize the commissioner.
  162. chip::FabricId fabricId;
  163. if (identity == kIdentityAlpha)
  164. {
  165. fabricId = kIdentityAlphaFabricId;
  166. }
  167. else if (identity == kIdentityBeta)
  168. {
  169. fabricId = kIdentityBetaFabricId;
  170. }
  171. else if (identity == kIdentityGamma)
  172. {
  173. fabricId = kIdentityGammaFabricId;
  174. }
  175. else
  176. {
  177. fabricId = strtoull(identity.c_str(), nullptr, 0);
  178. if (fabricId < kIdentityOtherFabricId)
  179. {
  180. ChipLogError(chipTool, "Invalid identity: %s", identity.c_str());
  181. return CHIP_ERROR_INVALID_ARGUMENT;
  182. }
  183. }
  184. return InitializeCommissioner(lookupKey, fabricId);
  185. }
  186. CHIP_ERROR CHIPCommand::Run()
  187. {
  188. ReturnErrorOnFailure(MaybeSetUpStack());
  189. CHIP_ERROR err = StartWaiting(GetWaitDuration());
  190. if (IsInteractive())
  191. {
  192. bool timedOut;
  193. // Give it 2 hours to run our cleanup; that should never get hit in practice.
  194. CHIP_ERROR cleanupErr = RunOnMatterQueue(RunCommandCleanup, chip::System::Clock::Seconds16(7200), &timedOut);
  195. VerifyOrDie(cleanupErr == CHIP_NO_ERROR);
  196. VerifyOrDie(!timedOut);
  197. }
  198. else
  199. {
  200. CleanupAfterRun();
  201. }
  202. MaybeTearDownStack();
  203. return err;
  204. }
  205. void CHIPCommand::StartTracing()
  206. {
  207. if (mTraceTo.HasValue())
  208. {
  209. for (const auto & destination : mTraceTo.Value())
  210. {
  211. mTracingSetup.EnableTracingFor(destination.c_str());
  212. }
  213. }
  214. #if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
  215. chip::trace::InitTrace();
  216. if (mTraceFile.HasValue())
  217. {
  218. chip::trace::AddTraceStream(new chip::trace::TraceStreamFile(mTraceFile.Value()));
  219. }
  220. else if (mTraceLog.HasValue() && mTraceLog.Value())
  221. {
  222. chip::trace::AddTraceStream(new chip::trace::TraceStreamLog());
  223. }
  224. if (mTraceDecode.HasValue() && mTraceDecode.Value())
  225. {
  226. chip::trace::TraceDecoderOptions options;
  227. // The interaction model protocol is already logged, so just disable logging those.
  228. options.mEnableProtocolInteractionModelResponse = false;
  229. chip::trace::TraceDecoder * decoder = new chip::trace::TraceDecoder();
  230. decoder->SetOptions(options);
  231. chip::trace::AddTraceStream(decoder);
  232. }
  233. #endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
  234. }
  235. void CHIPCommand::StopTracing()
  236. {
  237. mTracingSetup.StopTracing();
  238. #if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
  239. chip::trace::DeInitTrace();
  240. #endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
  241. }
  242. void CHIPCommand::SetIdentity(const char * identity)
  243. {
  244. std::string name = std::string(identity);
  245. if (name.compare(kIdentityAlpha) != 0 && name.compare(kIdentityBeta) != 0 && name.compare(kIdentityGamma) != 0 &&
  246. name.compare(kIdentityNull) != 0 && strtoull(name.c_str(), nullptr, 0) < kIdentityOtherFabricId)
  247. {
  248. ChipLogError(chipTool, "Unknown commissioner name: %s. Supported names are [%s, %s, %s, 4, 5...]", name.c_str(),
  249. kIdentityAlpha, kIdentityBeta, kIdentityGamma);
  250. chipDie();
  251. }
  252. mCommissionerName.SetValue(const_cast<char *>(identity));
  253. }
  254. std::string CHIPCommand::GetIdentity()
  255. {
  256. std::string name = mCommissionerName.HasValue() ? mCommissionerName.Value() : kIdentityAlpha;
  257. if (name.compare(kIdentityAlpha) != 0 && name.compare(kIdentityBeta) != 0 && name.compare(kIdentityGamma) != 0 &&
  258. name.compare(kIdentityNull) != 0)
  259. {
  260. chip::FabricId fabricId = strtoull(name.c_str(), nullptr, 0);
  261. if (fabricId >= kIdentityOtherFabricId)
  262. {
  263. // normalize name since it is used in persistent storage
  264. char s[24];
  265. sprintf(s, "%" PRIu64, fabricId);
  266. name = s;
  267. }
  268. else
  269. {
  270. ChipLogError(chipTool, "Unknown commissioner name: %s. Supported names are [%s, %s, %s, 4, 5...]", name.c_str(),
  271. kIdentityAlpha, kIdentityBeta, kIdentityGamma);
  272. chipDie();
  273. }
  274. }
  275. return name;
  276. }
  277. CHIP_ERROR CHIPCommand::GetIdentityNodeId(std::string identity, chip::NodeId * nodeId)
  278. {
  279. if (mCommissionerNodeId.HasValue())
  280. {
  281. *nodeId = mCommissionerNodeId.Value();
  282. return CHIP_NO_ERROR;
  283. }
  284. if (identity == kIdentityNull)
  285. {
  286. *nodeId = chip::kUndefinedNodeId;
  287. return CHIP_NO_ERROR;
  288. }
  289. ReturnLogErrorOnFailure(mCommissionerStorage.Init(identity.c_str(), GetStorageDirectory().ValueOr(nullptr)));
  290. *nodeId = mCommissionerStorage.GetLocalNodeId();
  291. return CHIP_NO_ERROR;
  292. }
  293. CHIP_ERROR CHIPCommand::GetIdentityRootCertificate(std::string identity, chip::ByteSpan & span)
  294. {
  295. if (identity == kIdentityNull)
  296. {
  297. return CHIP_ERROR_NOT_FOUND;
  298. }
  299. chip::NodeId nodeId;
  300. VerifyOrDie(GetIdentityNodeId(identity, &nodeId) == CHIP_NO_ERROR);
  301. CommissionerIdentity lookupKey{ identity, nodeId };
  302. auto item = mCommissioners.find(lookupKey);
  303. span = chip::ByteSpan(item->first.mRCAC, item->first.mRCACLen);
  304. return CHIP_NO_ERROR;
  305. }
  306. chip::FabricId CHIPCommand::CurrentCommissionerId()
  307. {
  308. chip::FabricId id;
  309. std::string name = GetIdentity();
  310. if (name.compare(kIdentityAlpha) == 0)
  311. {
  312. id = kIdentityAlphaFabricId;
  313. }
  314. else if (name.compare(kIdentityBeta) == 0)
  315. {
  316. id = kIdentityBetaFabricId;
  317. }
  318. else if (name.compare(kIdentityGamma) == 0)
  319. {
  320. id = kIdentityGammaFabricId;
  321. }
  322. else if (name.compare(kIdentityNull) == 0)
  323. {
  324. id = kIdentityNullFabricId;
  325. }
  326. else if ((id = strtoull(name.c_str(), nullptr, 0)) < kIdentityOtherFabricId)
  327. {
  328. VerifyOrDieWithMsg(false, chipTool, "Unknown commissioner name: %s. Supported names are [%s, %s, %s, 4, 5...]",
  329. name.c_str(), kIdentityAlpha, kIdentityBeta, kIdentityGamma);
  330. }
  331. return id;
  332. }
  333. chip::Controller::DeviceCommissioner & CHIPCommand::CurrentCommissioner()
  334. {
  335. return GetCommissioner(GetIdentity());
  336. }
  337. chip::Controller::DeviceCommissioner & CHIPCommand::GetCommissioner(std::string identity)
  338. {
  339. // We don't have a great way to handle commissioner setup failures here.
  340. // This only matters for commands (like TestCommand) that involve multiple
  341. // identities.
  342. VerifyOrDie(EnsureCommissionerForIdentity(identity) == CHIP_NO_ERROR);
  343. chip::NodeId nodeId;
  344. VerifyOrDie(GetIdentityNodeId(identity, &nodeId) == CHIP_NO_ERROR);
  345. CommissionerIdentity lookupKey{ identity, nodeId };
  346. auto item = mCommissioners.find(lookupKey);
  347. VerifyOrDie(item != mCommissioners.end());
  348. return *item->second;
  349. }
  350. void CHIPCommand::ShutdownCommissioner(const CommissionerIdentity & key)
  351. {
  352. mCommissioners[key].get()->Shutdown();
  353. }
  354. CHIP_ERROR CHIPCommand::InitializeCommissioner(CommissionerIdentity & identity, chip::FabricId fabricId)
  355. {
  356. std::unique_ptr<ChipDeviceCommissioner> commissioner = std::make_unique<ChipDeviceCommissioner>();
  357. chip::Controller::SetupParams commissionerParams;
  358. ReturnLogErrorOnFailure(mCredIssuerCmds->SetupDeviceAttestation(commissionerParams, sTrustStore));
  359. chip::Crypto::P256Keypair ephemeralKey;
  360. if (fabricId != chip::kUndefinedFabricId)
  361. {
  362. // TODO - OpCreds should only be generated for pairing command
  363. // store the credentials in persistent storage, and
  364. // generate when not available in the storage.
  365. ReturnLogErrorOnFailure(mCommissionerStorage.Init(identity.mName.c_str(), GetStorageDirectory().ValueOr(nullptr)));
  366. if (mUseMaxSizedCerts.HasValue())
  367. {
  368. auto option = CredentialIssuerCommands::CredentialIssuerOptions::kMaximizeCertificateSizes;
  369. mCredIssuerCmds->SetCredentialIssuerOption(option, mUseMaxSizedCerts.Value());
  370. }
  371. ReturnLogErrorOnFailure(mCredIssuerCmds->InitializeCredentialsIssuer(mCommissionerStorage));
  372. chip::MutableByteSpan nocSpan(identity.mNOC);
  373. chip::MutableByteSpan icacSpan(identity.mICAC);
  374. chip::MutableByteSpan rcacSpan(identity.mRCAC);
  375. ReturnLogErrorOnFailure(ephemeralKey.Initialize(chip::Crypto::ECPKeyTarget::ECDSA));
  376. ReturnLogErrorOnFailure(mCredIssuerCmds->GenerateControllerNOCChain(identity.mLocalNodeId, fabricId,
  377. mCommissionerStorage.GetCommissionerCATs(),
  378. ephemeralKey, rcacSpan, icacSpan, nocSpan));
  379. identity.mRCACLen = rcacSpan.size();
  380. identity.mICACLen = icacSpan.size();
  381. identity.mNOCLen = nocSpan.size();
  382. commissionerParams.operationalKeypair = &ephemeralKey;
  383. commissionerParams.controllerRCAC = rcacSpan;
  384. commissionerParams.controllerICAC = icacSpan;
  385. commissionerParams.controllerNOC = nocSpan;
  386. commissionerParams.permitMultiControllerFabrics = true;
  387. }
  388. // TODO: Initialize IPK epoch key in ExampleOperationalCredentials issuer rather than relying on DefaultIpkValue
  389. commissionerParams.operationalCredentialsDelegate = mCredIssuerCmds->GetCredentialIssuer();
  390. commissionerParams.controllerVendorId = mCommissionerVendorId.ValueOr(chip::VendorId::TestVendor1);
  391. ReturnLogErrorOnFailure(DeviceControllerFactory::GetInstance().SetupCommissioner(commissionerParams, *(commissioner.get())));
  392. if (identity.mName != kIdentityNull)
  393. {
  394. // Initialize Group Data, including IPK
  395. chip::FabricIndex fabricIndex = commissioner->GetFabricIndex();
  396. uint8_t compressed_fabric_id[sizeof(uint64_t)];
  397. chip::MutableByteSpan compressed_fabric_id_span(compressed_fabric_id);
  398. ReturnLogErrorOnFailure(commissioner->GetCompressedFabricIdBytes(compressed_fabric_id_span));
  399. ReturnLogErrorOnFailure(chip::GroupTesting::InitData(&sGroupDataProvider, fabricIndex, compressed_fabric_id_span));
  400. // Configure the default IPK for all fabrics used by CHIP-tool. The epoch
  401. // key is the same, but the derived keys will be different for each fabric.
  402. chip::ByteSpan defaultIpk = chip::GroupTesting::DefaultIpkValue::GetDefaultIpk();
  403. ReturnLogErrorOnFailure(
  404. chip::Credentials::SetSingleIpkEpochKey(&sGroupDataProvider, fabricIndex, defaultIpk, compressed_fabric_id_span));
  405. }
  406. mCommissioners[identity] = std::move(commissioner);
  407. return CHIP_NO_ERROR;
  408. }
  409. void CHIPCommand::RunQueuedCommand(intptr_t commandArg)
  410. {
  411. auto * command = reinterpret_cast<CHIPCommand *>(commandArg);
  412. CHIP_ERROR err = command->EnsureCommissionerForIdentity(command->GetIdentity());
  413. if (err == CHIP_NO_ERROR)
  414. {
  415. err = command->RunCommand();
  416. }
  417. if (err != CHIP_NO_ERROR)
  418. {
  419. command->SetCommandExitStatus(err);
  420. }
  421. }
  422. void CHIPCommand::RunCommandCleanup(intptr_t commandArg)
  423. {
  424. auto * command = reinterpret_cast<CHIPCommand *>(commandArg);
  425. command->CleanupAfterRun();
  426. command->StopWaiting();
  427. }
  428. void CHIPCommand::CleanupAfterRun()
  429. {
  430. assertChipStackLockedByCurrentThread();
  431. bool deferCleanup = (IsInteractive() && DeferInteractiveCleanup());
  432. Shutdown();
  433. if (deferCleanup)
  434. {
  435. sDeferredCleanups.insert(this);
  436. }
  437. else
  438. {
  439. Cleanup();
  440. }
  441. }
  442. CHIP_ERROR CHIPCommand::RunOnMatterQueue(MatterWorkCallback callback, chip::System::Clock::Timeout timeout, bool * timedOut)
  443. {
  444. {
  445. std::lock_guard<std::mutex> lk(cvWaitingForResponseMutex);
  446. mWaitingForResponse = true;
  447. }
  448. auto err = chip::DeviceLayer::PlatformMgr().ScheduleWork(callback, reinterpret_cast<intptr_t>(this));
  449. if (CHIP_NO_ERROR != err)
  450. {
  451. {
  452. std::lock_guard<std::mutex> lk(cvWaitingForResponseMutex);
  453. mWaitingForResponse = false;
  454. }
  455. return err;
  456. }
  457. auto waitingUntil = std::chrono::system_clock::now() + std::chrono::duration_cast<std::chrono::seconds>(timeout);
  458. {
  459. std::unique_lock<std::mutex> lk(cvWaitingForResponseMutex);
  460. *timedOut = !cvWaitingForResponse.wait_until(lk, waitingUntil, [this]() { return !this->mWaitingForResponse; });
  461. }
  462. return CHIP_NO_ERROR;
  463. }
  464. #if !CONFIG_USE_SEPARATE_EVENTLOOP
  465. static void OnResponseTimeout(chip::System::Layer *, void * appState)
  466. {
  467. (reinterpret_cast<CHIPCommand *>(appState))->SetCommandExitStatus(CHIP_ERROR_TIMEOUT);
  468. }
  469. #endif // !CONFIG_USE_SEPARATE_EVENTLOOP
  470. CHIP_ERROR CHIPCommand::StartWaiting(chip::System::Clock::Timeout duration)
  471. {
  472. #if CONFIG_USE_SEPARATE_EVENTLOOP
  473. // ServiceEvents() calls StartEventLoopTask(), which is paired with the StopEventLoopTask() below.
  474. if (!IsInteractive())
  475. {
  476. ReturnLogErrorOnFailure(DeviceControllerFactory::GetInstance().ServiceEvents());
  477. }
  478. if (duration.count() == 0)
  479. {
  480. mCommandExitStatus = RunCommand();
  481. }
  482. else
  483. {
  484. bool timedOut;
  485. CHIP_ERROR err = RunOnMatterQueue(RunQueuedCommand, duration, &timedOut);
  486. if (CHIP_NO_ERROR != err)
  487. {
  488. return err;
  489. }
  490. if (timedOut)
  491. {
  492. mCommandExitStatus = CHIP_ERROR_TIMEOUT;
  493. }
  494. }
  495. if (!IsInteractive())
  496. {
  497. LogErrorOnFailure(chip::DeviceLayer::PlatformMgr().StopEventLoopTask());
  498. }
  499. #else
  500. chip::DeviceLayer::PlatformMgr().ScheduleWork(RunQueuedCommand, reinterpret_cast<intptr_t>(this));
  501. ReturnLogErrorOnFailure(chip::DeviceLayer::SystemLayer().StartTimer(duration, OnResponseTimeout, this));
  502. chip::DeviceLayer::PlatformMgr().RunEventLoop();
  503. #endif // CONFIG_USE_SEPARATE_EVENTLOOP
  504. return mCommandExitStatus;
  505. }
  506. void CHIPCommand::StopWaiting()
  507. {
  508. #if CONFIG_USE_SEPARATE_EVENTLOOP
  509. {
  510. std::lock_guard<std::mutex> lk(cvWaitingForResponseMutex);
  511. mWaitingForResponse = false;
  512. }
  513. cvWaitingForResponse.notify_all();
  514. #else // CONFIG_USE_SEPARATE_EVENTLOOP
  515. LogErrorOnFailure(chip::DeviceLayer::PlatformMgr().StopEventLoopTask());
  516. #endif // CONFIG_USE_SEPARATE_EVENTLOOP
  517. }
  518. void CHIPCommand::ExecuteDeferredCleanups(intptr_t ignored)
  519. {
  520. for (auto * cmd : sDeferredCleanups)
  521. {
  522. cmd->Cleanup();
  523. }
  524. sDeferredCleanups.clear();
  525. }