From f0bbe33ed9171f23482ea1e763db4b0e709ffd1e Mon Sep 17 00:00:00 2001 From: lezhan Date: Mon, 6 May 2024 06:21:05 +0000 Subject: [PATCH 01/13] [tlv] add new tlvs for network diagnostic libotcommissioner.jar, a versatile Java library, provides support for wide range of TMF message transactions, including MeshCop protocols and diagnostic TLVs. This PR focuses on integrating all the diagnostic TLVs, as defined in the spec `10.11.3` into the library's TLV module --- src/library/tlv.cpp | 65 +++++++++++++++++++++++++++++++++++++++++++++ src/library/tlv.hpp | 33 +++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/src/library/tlv.cpp b/src/library/tlv.cpp index 70405817..efeddde9 100644 --- a/src/library/tlv.cpp +++ b/src/library/tlv.cpp @@ -220,6 +220,71 @@ bool Tlv::IsValid() const { return false; } + else if (mScope == Scope::kNetworkDiag) + { + switch (mType) + { + // Network disgnostic layer TLVs + case Type::kNetworkDiagExtMacAddress: + return length == 8; + case Type::kNetworkDiagMacAddress: + return length == 2; + case Type::kNetworkDiagMode: + return length == 1; + case Type::kNetworkDiagTimeout: + return length == 4; + case Type::kNetworkDiagRoute64: + return length >= 4; + case Type::kNetworkDiagLeaderData: + return length == 8; + case Type::kNetworkDiagNetworkData: + return true; + case Type::kNetworkDiagIpv6Address: + return (length % 16 == 0) && (length / 16 >= 1 && length / 16 <= 15); + case Type::kNetworkDiagMacCounters: + return length <= 36; + case Type::kNetworkDiagBatteryLevel: + return length == 1; + case Type::kNetworkDiagSupplyVoltage: + return length == 2; + case Type::kNetworkDiagChildTable: + return true; // list of 0 or more child entry data + case Type::kNetworkDiagChannelPages: + return length >= 1; // 1 or more 8-bit integers + case Type::kNetworkDiagTypeList: + return length >= 1; // 1 or more 8-bit integers + case Type::kNetworkDiagMaxChildTimeout: + return length == 4; + case Type::kNetworkDiagLDevIDSubjectPubKeyInfo: + return true; + case Type::kNetworkDiagIDevIDCert: + return true; + case Type::kNetworkDiagEui64: + return length == 8; + case Type::kNetworkDiagVersion: + return length == 2; + case Type::kNetworkDiagVendorName: + return length <= 4; + case Type::kNetworkDiagVendorModel: + return length <= 4; + case Type::kNetworkDiagVendorSWVersion: + return length <= 2; + case Type::kNetworkDiagChild: + return length <= 43; + case Type::kNetworkDiagChildIpv6Address: + return (length % 16 == 0) && (length / 16 >= 1 && length / 16 <= 15); + case Type::kNetworkDiagRouterNeighbor: + return length <= 24; + case Type::kNetworkDiagAnswer: + return length == 2; + case Type::kNetworkDiagQueryID: + return length == 2; + case Type::kNetworkDiagMleCounters: + return length <= 66; + default: + return false; + } + } switch (mType) { diff --git a/src/library/tlv.hpp b/src/library/tlv.hpp index b478767a..e2b52eaa 100644 --- a/src/library/tlv.hpp +++ b/src/library/tlv.hpp @@ -63,6 +63,7 @@ enum class Scope : uint8_t kMeshCoP = 0, kThread, kMeshLink, + kNetworkDiag, }; enum class Type : uint8_t @@ -139,6 +140,38 @@ enum class Type : uint8_t kCommissionerPenSignature = 70, kDiscoveryRequest = 128, kDiscoveryResponse = 129, + + // TMF Network Diagnositcs TLVs + kNetworkDiagExtMacAddress = 0, + kNetworkDiagMacAddress = 1, + kNetworkDiagMode = 2, + kNetworkDiagTimeout = 3, + kNetworkDiagConnectivity = 4, + kNetworkDiagRoute64 = 5, + kNetworkDiagLeaderData = 6, + kNetworkDiagNetworkData = 7, + kNetworkDiagIpv6Address = 8, + kNetworkDiagMacCounters = 9, + kNetworkDiagBatteryLevel = 14, + kNetworkDiagSupplyVoltage = 15, + kNetworkDiagChildTable = 16, + kNetworkDiagChannelPages = 17, + kNetworkDiagTypeList = 18, + kNetworkDiagMaxChildTimeout = 19, + kNetworkDiagLDevIDSubjectPubKeyInfo = 20, + kNetworkDiagIDevIDCert = 21, + kNetworkDiagEui64 = 23, + kNetworkDiagVersion = 24, + kNetworkDiagVendorName = 25, + kNetworkDiagVendorModel = 26, + kNetworkDiagVendorSWVersion = 27, + kNetworkDiagThreadStackVersion = 28, + kNetworkDiagChild = 29, + kNetworkDiagChildIpv6Address = 30, + kNetworkDiagRouterNeighbor = 31, + kNetworkDiagAnswer = 32, + kNetworkDiagQueryID = 33, + kNetworkDiagMleCounters = 34, }; using TlvPtr = std::shared_ptr; From 1cc832269f72642682773d05c2933b2aec8ef0b7 Mon Sep 17 00:00:00 2001 From: lezhan Date: Mon, 6 May 2024 06:21:05 +0000 Subject: [PATCH 02/13] [tlv] add new tlvs for network diagnostic libotcommissioner.jar, a versatile Java library, provides support for wide range of TMF message transactions, including MeshCop protocols and diagnostic TLVs. This PR focuses on integrating all the diagnostic TLVs, as defined in the spec `10.11.3` into the library's TLV module --- src/library/tlv.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/library/tlv.cpp b/src/library/tlv.cpp index efeddde9..d5cae8f1 100644 --- a/src/library/tlv.cpp +++ b/src/library/tlv.cpp @@ -226,9 +226,15 @@ bool Tlv::IsValid() const { // Network disgnostic layer TLVs case Type::kNetworkDiagExtMacAddress: +<<<<<<< HEAD return length == 8; case Type::kNetworkDiagMacAddress: return length == 2; +======= + return length >= 8; + case Type::kNetworkDiagMacAddress: + return length >= 2; +>>>>>>> 20da654 ([tlv] add new tlvs for network diagnostic) case Type::kNetworkDiagMode: return length == 1; case Type::kNetworkDiagTimeout: From af7f86f817be08a6ab6a79afd2a913d26e8c3d83 Mon Sep 17 00:00:00 2001 From: lezhan Date: Mon, 6 May 2024 06:21:05 +0000 Subject: [PATCH 03/13] [tlv] add new tlvs for network diagnostic libotcommissioner.jar, a versatile Java library, provides support for wide range of TMF message transactions, including MeshCop protocols and diagnostic TLVs. This PR focuses on integrating all the diagnostic TLVs, as defined in the spec `10.11.3` into the library's TLV module --- src/library/tlv.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/library/tlv.cpp b/src/library/tlv.cpp index d5cae8f1..0dc7603e 100644 --- a/src/library/tlv.cpp +++ b/src/library/tlv.cpp @@ -226,19 +226,15 @@ bool Tlv::IsValid() const { // Network disgnostic layer TLVs case Type::kNetworkDiagExtMacAddress: -<<<<<<< HEAD - return length == 8; - case Type::kNetworkDiagMacAddress: - return length == 2; -======= return length >= 8; case Type::kNetworkDiagMacAddress: return length >= 2; ->>>>>>> 20da654 ([tlv] add new tlvs for network diagnostic) case Type::kNetworkDiagMode: return length == 1; case Type::kNetworkDiagTimeout: return length == 4; + case Type::kNetworkDiagConnectivity: + return true; case Type::kNetworkDiagRoute64: return length >= 4; case Type::kNetworkDiagLeaderData: From 8ada05ffaeec6ea83da7028fd6091be8ff128a40 Mon Sep 17 00:00:00 2001 From: Kangping Date: Mon, 6 May 2024 23:28:16 +0800 Subject: [PATCH 04/13] [build] output test files to ./tmp (#265) Current unit tests are writing intermediate testing files to current dir. This is polluting the source dir when executing the tests in the source root dir. This commit updates the unit tests to output the testing data files to a dedicated ./tmp dir and ignore dir tmp/ from git. --- .gitignore | 3 + src/app/cli/interpreter_test.cpp | 100 ++++++++------- src/app/cli/job_manager_test.cpp | 74 ++++++----- src/app/ps/persistent_storage_json_test.cpp | 135 +++++++++++--------- src/app/ps/registry_test.cpp | 8 +- 5 files changed, 169 insertions(+), 151 deletions(-) diff --git a/.gitignore b/.gitignore index 537cf8ba..ed9f0ed7 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,9 @@ Makefile.in /build cmake-build-* +# Test +/tmp + #tools .vscode .idea diff --git a/src/app/cli/interpreter_test.cpp b/src/app/cli/interpreter_test.cpp index 4ebefba7..a01bc572 100644 --- a/src/app/cli/interpreter_test.cpp +++ b/src/app/cli/interpreter_test.cpp @@ -97,8 +97,8 @@ class InterpreterTestSuite : public testing::Test void InitContext(TestContext &ctx) { // Minimum test setup: create config file - const std::string configFile = "./config"; - auto error = WriteFile("{\"ThreadSMRoot\": \"./\"}", configFile); + const std::string configFile = "./tmp/config"; + auto error = WriteFile("{\"ThreadSMRoot\": \"./tmp\"}", configFile); ASSERT_EQ(error.GetCode(), ErrorCode::kNone); ASSERT_NE(ctx.mDefaultCommissionerObject, nullptr); @@ -108,7 +108,7 @@ class InterpreterTestSuite : public testing::Test DoAll(WithArg<0>([&](std::shared_ptr &a) { a = ctx.mDefaultCommissionerObject; }), Return(Error{}))); - auto result = ctx.mInterpreter.Init("./config", ""); + auto result = ctx.mInterpreter.Init("./tmp/config", ""); ASSERT_EQ(result.GetCode(), ErrorCode::kNone); ctx.mRegistry = ctx.mInterpreter.mRegistry.get(); @@ -116,6 +116,12 @@ class InterpreterTestSuite : public testing::Test // Add formal default PSKc ctx.mInterpreter.mJobManager->mDefaultConf.mPSKc = {'1', '0'}; } + + void SetUp() override + { + ASSERT_TRUE(system("rm -rf tmp") == 0); + ASSERT_TRUE(system("mkdir -p tmp") == 0); + } }; TEST_F(InterpreterTestSuite, TestInit) @@ -660,10 +666,10 @@ TEST_F(InterpreterTestSuite, IESV_SingleImportFileMustPass) }\n\ }"; - EXPECT_EQ(WriteFile(jsonStr, "./json.json").GetCode(), ErrorCode::kNone); + EXPECT_EQ(WriteFile(jsonStr, "./tmp/json.json").GetCode(), ErrorCode::kNone); EXPECT_CALL(*commissionerAppMock, SetActiveDataset(_)).WillOnce(Return(Error{})); - expr = ctx.mInterpreter.ParseExpression("opdataset set active --import ./json.json"); + expr = ctx.mInterpreter.ParseExpression("opdataset set active --import ./tmp/json.json"); auto value = ctx.mInterpreter.Eval(expr); EXPECT_TRUE(value.HasNoError()); } @@ -1113,10 +1119,10 @@ TEST_F(InterpreterTestSuite, PC_Token) value = ctx.mInterpreter.Eval(expr); EXPECT_TRUE(value.HasNoError()); - EXPECT_EQ(WriteFile("123aef", "./token").GetCode(), ErrorCode::kNone); + EXPECT_EQ(WriteFile("123aef", "./tmp/token").GetCode(), ErrorCode::kNone); EXPECT_CALL(*ctx.mDefaultCommissionerObject, SetToken(_)).WillOnce(Return(Error{})); EXPECT_CALL(*ctx.mDefaultCommissionerObject, GetToken()).WillOnce(ReturnRef(token)); - expr = ctx.mInterpreter.ParseExpression("token set ./token"); + expr = ctx.mInterpreter.ParseExpression("token set ./tmp/token"); value = ctx.mInterpreter.Eval(expr); EXPECT_TRUE(value.HasNoError()); } @@ -1129,7 +1135,7 @@ TEST_F(InterpreterTestSuite, PC_TokenWithCCM) // prepare CCM network record const std::string kDomainName = "domain1"; const std::string kNetworkName = "net1"; - const std::string kSmPath = "./dom/" + kDomainName + "/"; + const std::string kSmPath = "./tmp/dom/" + kDomainName + "/"; XpanId xpanCcm{1}; BorderAgent::State baStateCcm{BorderAgent::State::ConnectionMode::kX509Connection, 0, 0, 0, 0}; @@ -1164,15 +1170,15 @@ TEST_F(InterpreterTestSuite, PC_TokenWithCCM) EXPECT_EQ(ctx.mInterpreter.mRegistry->SetCurrentNetwork(xpanCcm), RegistryStatus::kSuccess); expr = ctx.mInterpreter.ParseExpression("token request 127.0.0.1 2001"); value = ctx.mInterpreter.Eval(expr); - EXPECT_TRUE(value.HasNoError()); + EXPECT_TRUE(value.HasNoError()) << "value is " << value.ToString(); const ByteArray token = {'1', '2', '3', 'a', 'e', 'f'}; EXPECT_CALL(*pcaMock, SetToken(_)).WillOnce(Return(Error{})); // note: again, we do not expect GetToken() here, same reason - EXPECT_EQ(WriteFile("123aef", "./token").GetCode(), ErrorCode::kNone); - expr = ctx.mInterpreter.ParseExpression("token set ./token"); + EXPECT_EQ(WriteFile("123aef", "./tmp/token").GetCode(), ErrorCode::kNone); + expr = ctx.mInterpreter.ParseExpression("token set ./tmp/token"); value = ctx.mInterpreter.Eval(expr); EXPECT_TRUE(value.HasNoError()); } @@ -1185,7 +1191,7 @@ TEST_F(InterpreterTestSuite, PC_TokenWithNonCCM) // prepare non-CCM network record const std::string kDomainName = "DefaultDomain"; const std::string kNetworkName = "net2"; - const std::string kSmPath = "./nwk/" + kNetworkName + "/"; + const std::string kSmPath = "./tmp/nwk/" + kNetworkName + "/"; XpanId xpanNonCcm{2}; BorderAgent::State baStateNonCcm{BorderAgent::State::ConnectionMode::kPSKcConnection, 0, 0, 0, 0}; @@ -1223,8 +1229,8 @@ TEST_F(InterpreterTestSuite, PC_TokenWithNonCCM) // note: we do not expect GetToken() here as no default config // update to happen with a network selected - EXPECT_EQ(WriteFile("123aef", "./token").GetCode(), ErrorCode::kNone); - expr = ctx.mInterpreter.ParseExpression("token set ./token"); + EXPECT_EQ(WriteFile("123aef", "./tmp/token").GetCode(), ErrorCode::kNone); + expr = ctx.mInterpreter.ParseExpression("token set ./tmp/token"); value = ctx.mInterpreter.Eval(expr); EXPECT_TRUE(value.HasNoError()); } @@ -1255,8 +1261,8 @@ TEST_F(InterpreterTestSuite, PC_TokenWithNone) // GetToken() to be called on default commissioner instance EXPECT_CALL(*ctx.mDefaultCommissionerObject, GetToken()).WillOnce(ReturnRef(token)); - EXPECT_EQ(WriteFile("123aef", "./token").GetCode(), ErrorCode::kNone); - expr = ctx.mInterpreter.ParseExpression("token set ./token"); + EXPECT_EQ(WriteFile("123aef", "./tmp/token").GetCode(), ErrorCode::kNone); + expr = ctx.mInterpreter.ParseExpression("token set ./tmp/token"); value = ctx.mInterpreter.Eval(expr); EXPECT_TRUE(value.HasNoError()); } @@ -1823,17 +1829,14 @@ TEST_F(InterpreterTestSuite, PC_OpdatasetGetActive) EXPECT_EQ(ctx.mRegistry->mStorage->Get(nwk_id, nwk), PersistentStorage::Status::kSuccess); EXPECT_EQ(nwk.mPan.mValue, 0x0001); - EXPECT_EQ(system("rm -f ./aods.json"), 0); - EXPECT_NE(PathExists("./aods.json").GetCode(), ErrorCode::kNone); - - expr = ctx.mInterpreter.ParseExpression("opdataset get active --export ./aods.json"); + expr = ctx.mInterpreter.ParseExpression("opdataset get active --export ./tmp/aods.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_TRUE(value.HasNoError()); ctx.mInterpreter.PrintOrExport(value); - EXPECT_EQ(PathExists("./aods.json").GetCode(), ErrorCode::kNone); + EXPECT_EQ(PathExists("./tmp/aods.json").GetCode(), ErrorCode::kNone); std::string jsonStr; - EXPECT_EQ(ReadFile(jsonStr, "./aods.json").GetCode(), ErrorCode::kNone); + EXPECT_EQ(ReadFile(jsonStr, "./tmp/aods.json").GetCode(), ErrorCode::kNone); nlohmann::json json = nlohmann::json::parse(jsonStr); EXPECT_TRUE(json.contains("PanId")); EXPECT_STREQ("0x0001", json.at("PanId").get().c_str()); @@ -2109,7 +2112,7 @@ TEST_F(InterpreterTestSuite, PC_BrScanExport) Interpreter::Expression expr; Interpreter::Value value; - std::string jsonFileName = "./br-list.json"; + std::string jsonFileName = "./tmp/br-list.json"; EXPECT_EQ(system(fmt::format("rm -rf {}", jsonFileName).c_str()), 0); EXPECT_NE(PathExists(jsonFileName).GetCode(), ErrorCode::kNone); @@ -2139,8 +2142,7 @@ TEST_F(InterpreterTestSuite, PC_BrScanExportDirAbsent) Interpreter::Expression expr; Interpreter::Value value; - std::string jsonFileName = "./tmpdir/br-list.json"; - ASSERT_EQ(system("rm -rf ./tmpdir"), 0); + std::string jsonFileName = "./tmp/br-list.json"; expr = ctx.mInterpreter.ParseExpression(std::string("br scan --timeout 1 --export ") + jsonFileName); value = ctx.mInterpreter.Eval(expr); EXPECT_TRUE(value.HasNoError()); @@ -2198,23 +2200,23 @@ TEST_F(InterpreterTestSuite, PC_BrAddNoMandatoryFail) Interpreter::Expression expr; Interpreter::Value value; - EXPECT_EQ(WriteFile(brJsonNoAddr, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonNoAddr, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); - EXPECT_EQ(WriteFile(brJsonNoPort, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonNoPort, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); - EXPECT_EQ(WriteFile(brJsonNoVersion, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonNoVersion, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); - EXPECT_EQ(WriteFile(brJsonNoState, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonNoState, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); } @@ -2267,23 +2269,23 @@ n]"; Interpreter::Expression expr; Interpreter::Value value; - EXPECT_EQ(WriteFile(brJsonNwkName, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonNwkName, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); - EXPECT_EQ(WriteFile(brJsonNwkNameZeroXPan, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonNwkNameZeroXPan, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); - EXPECT_EQ(WriteFile(brJsonDomainName, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonDomainName, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); - EXPECT_EQ(WriteFile(brJsonDomainNameZeroXPan, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonDomainNameZeroXPan, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); } @@ -2349,18 +2351,18 @@ TEST_F(InterpreterTestSuite, PC_BrAddInterObjectInconsistencyFail) Interpreter::Expression expr; Interpreter::Value value; - EXPECT_EQ(WriteFile(brJsonSameAddr, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonSameAddr, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); - EXPECT_EQ(WriteFile(brJsonSameXPanDifferentNwkNames, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonSameXPanDifferentNwkNames, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); - EXPECT_EQ(WriteFile(brJsonSameXPanDifferentDomains, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJsonSameXPanDifferentDomains, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_FALSE(value.HasNoError()); } @@ -2417,8 +2419,8 @@ TEST_F(InterpreterTestSuite, PC_BrAdd) Interpreter::Expression expr; Interpreter::Value value; - EXPECT_EQ(WriteFile(brJson, "./json.json"), Error{}); - expr = ctx.mInterpreter.ParseExpression("br add ./json.json"); + EXPECT_EQ(WriteFile(brJson, "./tmp/json.json"), Error{}); + expr = ctx.mInterpreter.ParseExpression("br add ./tmp/json.json"); value = ctx.mInterpreter.Eval(expr); EXPECT_TRUE(value.HasNoError()); diff --git a/src/app/cli/job_manager_test.cpp b/src/app/cli/job_manager_test.cpp index acab6733..ad9705fd 100644 --- a/src/app/cli/job_manager_test.cpp +++ b/src/app/cli/job_manager_test.cpp @@ -119,6 +119,12 @@ class JobManagerTestSuite : public testing::Test EXPECT_EQ(aContext.mJobManager.Init(aContext.mConf).mCode, ErrorCode::kNone); aContext.mInterpreter.mRegistry = aContext.mRegistry; } + + void SetUp() override + { + ASSERT_TRUE(system("rm -rf tmp") == 0); + ASSERT_TRUE(system("mkdir -p tmp") == 0); + } }; TEST_F(JobManagerTestSuite, TestInit) @@ -321,23 +327,22 @@ TEST_F(JobManagerTestSuite, StartCancel) TEST_F(JobManagerTestSuite, MalformedCredentialsJobCreateFailsByXPan) { - // Remove './nwk' subtree - ASSERT_EQ(system("rm -rf ./dom ./nwk"), 0); + ASSERT_EQ(system("rm -rf ./tmp/dom ./tmp/nwk"), 0); - EXPECT_EQ(mkdir("./nwk", 0777), 0); - EXPECT_EQ(mkdir("./nwk/0000000000000001", 0777), 0); - EXPECT_EQ(mkdir("./nwk/0000000000000002", 0777), 0); - EXPECT_EQ(mkdir("./nwk/0000000000000003", 0777), 0); + EXPECT_EQ(mkdir("./tmp/nwk", 0777), 0); + EXPECT_EQ(mkdir("./tmp/nwk/0000000000000001", 0777), 0); + EXPECT_EQ(mkdir("./tmp/nwk/0000000000000002", 0777), 0); + EXPECT_EQ(mkdir("./tmp/nwk/0000000000000003", 0777), 0); // Loose credentials for Network 1 - EXPECT_EQ(WriteFile("1", "./nwk/0000000000000001/ca.pem").mCode, ErrorCode::kNone); - EXPECT_EQ(WriteFile("1", "./nwk/0000000000000001/priv.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/0000000000000001/ca.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/0000000000000001/priv.pem").mCode, ErrorCode::kNone); // Loose credentials for Network 2 - EXPECT_EQ(WriteFile("1", "./nwk/0000000000000002/cert.pem").mCode, ErrorCode::kNone); - EXPECT_EQ(WriteFile("1", "./nwk/0000000000000002/priv.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/0000000000000002/cert.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/0000000000000002/priv.pem").mCode, ErrorCode::kNone); // Loose credentials for Network 3 - EXPECT_EQ(WriteFile("1", "./nwk/0000000000000003/cert.pem").mCode, ErrorCode::kNone); - EXPECT_EQ(WriteFile("1", "./nwk/0000000000000003/ca.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/0000000000000003/cert.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/0000000000000003/ca.pem").mCode, ErrorCode::kNone); TestContext ctx; SetInitialExpectations(ctx); @@ -399,23 +404,22 @@ TEST_F(JobManagerTestSuite, MalformedCredentialsJobCreateFailsByXPan) TEST_F(JobManagerTestSuite, MalformedCredentialsJobCreateFailsByName) { - // Remove './nwk' subtree - ASSERT_EQ(system("rm -rf ./dom ./nwk"), 0); + ASSERT_EQ(system("rm -rf ./tmp/dom ./tmp/nwk"), 0); - EXPECT_EQ(mkdir("./nwk", 0777), 0); - EXPECT_EQ(mkdir("./nwk/pan1", 0777), 0); - EXPECT_EQ(mkdir("./nwk/pan2", 0777), 0); - EXPECT_EQ(mkdir("./nwk/pan3", 0777), 0); + EXPECT_EQ(mkdir("./tmp/nwk", 0777), 0); + EXPECT_EQ(mkdir("./tmp/nwk/pan1", 0777), 0); + EXPECT_EQ(mkdir("./tmp/nwk/pan2", 0777), 0); + EXPECT_EQ(mkdir("./tmp/nwk/pan3", 0777), 0); // Loose credentials for Network 1 - EXPECT_EQ(WriteFile("1", "./nwk/pan1/ca.pem").mCode, ErrorCode::kNone); - EXPECT_EQ(WriteFile("1", "./nwk/pan1/priv.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/pan1/ca.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/pan1/priv.pem").mCode, ErrorCode::kNone); // Loose credentials for panwork 2 - EXPECT_EQ(WriteFile("1", "./nwk/pan2/cert.pem").mCode, ErrorCode::kNone); - EXPECT_EQ(WriteFile("1", "./nwk/pan2/priv.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/pan2/cert.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/pan2/priv.pem").mCode, ErrorCode::kNone); // Loose credentials for panwork 3 - EXPECT_EQ(WriteFile("1", "./nwk/pan3/cert.pem").mCode, ErrorCode::kNone); - EXPECT_EQ(WriteFile("1", "./nwk/pan3/ca.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/pan3/cert.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/nwk/pan3/ca.pem").mCode, ErrorCode::kNone); TestContext ctx; SetInitialExpectations(ctx); @@ -478,22 +482,22 @@ TEST_F(JobManagerTestSuite, MalformedCredentialsJobCreateFailsByName) TEST_F(JobManagerTestSuite, MalformedCredentialsJobCreateFailsByDomain) { // Remove SM subtrees - ASSERT_EQ(system("rm -rf ./dom ./nwk"), 0); + ASSERT_EQ(system("rm -rf ./tmp/dom ./tmp/nwk"), 0); - EXPECT_EQ(mkdir("./dom", 0777), 0); - EXPECT_EQ(mkdir("./dom/domain1", 0777), 0); - EXPECT_EQ(mkdir("./dom/domain2", 0777), 0); - EXPECT_EQ(mkdir("./dom/domain3", 0777), 0); + EXPECT_EQ(mkdir("./tmp/dom", 0777), 0); + EXPECT_EQ(mkdir("./tmp/dom/domain1", 0777), 0); + EXPECT_EQ(mkdir("./tmp/dom/domain2", 0777), 0); + EXPECT_EQ(mkdir("./tmp/dom/domain3", 0777), 0); // Loose credentials for domain1 - EXPECT_EQ(WriteFile("1", "./dom/domain1/ca.pem").mCode, ErrorCode::kNone); - EXPECT_EQ(WriteFile("1", "./dom/domain1/priv.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/dom/domain1/ca.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/dom/domain1/priv.pem").mCode, ErrorCode::kNone); // Loose credentials for domain2 - EXPECT_EQ(WriteFile("1", "./dom/domain2/cert.pem").mCode, ErrorCode::kNone); - EXPECT_EQ(WriteFile("1", "./dom/domain2/priv.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/dom/domain2/cert.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/dom/domain2/priv.pem").mCode, ErrorCode::kNone); // Loose credentials for domain 3 - EXPECT_EQ(WriteFile("1", "./dom/domain3/cert.pem").mCode, ErrorCode::kNone); - EXPECT_EQ(WriteFile("1", "./dom/domain3/ca.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/dom/domain3/cert.pem").mCode, ErrorCode::kNone); + EXPECT_EQ(WriteFile("1", "./tmp/dom/domain3/ca.pem").mCode, ErrorCode::kNone); TestContext ctx; SetInitialExpectations(ctx); diff --git a/src/app/ps/persistent_storage_json_test.cpp b/src/app/ps/persistent_storage_json_test.cpp index 34101c92..b51ee828 100644 --- a/src/app/ps/persistent_storage_json_test.cpp +++ b/src/app/ps/persistent_storage_json_test.cpp @@ -31,46 +31,59 @@ * The file implements unit tests for JSON-based persistent storage */ +#include +#include #include #include "persistent_storage_json.hpp" #include "app/border_agent.hpp" -#include - using namespace ot::commissioner::persistent_storage; using namespace ot::commissioner; -TEST(PSJson, CreateDefaultIfNotExists) +class PersistentStorageJsonTestSuite : public testing::Test +{ +public: + PersistentStorageJsonTestSuite() = default; + virtual ~PersistentStorageJsonTestSuite() = default; + + void SetUp() override + { + ASSERT_TRUE(system("rm -rf tmp") == 0); + ASSERT_TRUE(system("mkdir -p tmp") == 0); + } +}; + +TEST(PersistentStorageJsonTestSuite, CreateDefaultIfNotExists) { - PersistentStorageJson psj("./test_ps.json"); + PersistentStorageJson psj("./tmp/test_ps.json"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, ReadEmptyFile) +TEST(PersistentStorageJsonTestSuite, ReadEmptyFile) { - std::ofstream testTmp("./test.tmp"); + std::ofstream testTmp("./tmp/test.tmp"); testTmp.close(); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, ReadNonEmptyDefault) +TEST(PersistentStorageJsonTestSuite, ReadNonEmptyDefault) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, AddRegistrar) +TEST(PersistentStorageJsonTestSuite, AddRegistrar) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -86,9 +99,9 @@ TEST(PSJson, AddRegistrar) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, AddDomain) +TEST(PersistentStorageJsonTestSuite, AddDomain) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -104,12 +117,12 @@ TEST(PSJson, AddDomain) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, AddNetwork) +TEST(PersistentStorageJsonTestSuite, AddNetwork) { // Make the test independent - unlink("./test.tmp"); + unlink("./tmp/test.tmp"); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -131,9 +144,9 @@ TEST(PSJson, AddNetwork) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, AddBorderRouter) +TEST(PersistentStorageJsonTestSuite, AddBorderRouter) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -164,9 +177,9 @@ TEST(PSJson, AddBorderRouter) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, DelRegistrar) +TEST(PersistentStorageJsonTestSuite, DelRegistrar) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -178,9 +191,9 @@ TEST(PSJson, DelRegistrar) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, DelDomain) +TEST(PersistentStorageJsonTestSuite, DelDomain) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -192,7 +205,7 @@ TEST(PSJson, DelDomain) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, DelNetwork) +TEST(PersistentStorageJsonTestSuite, DelNetwork) { PersistentStorageJson psj(""); @@ -214,9 +227,9 @@ TEST(PSJson, DelNetwork) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, DelBorderRouter) +TEST(PersistentStorageJsonTestSuite, DelBorderRouter) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -228,9 +241,9 @@ TEST(PSJson, DelBorderRouter) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, GetRegistrarFromEmpty) +TEST(PersistentStorageJsonTestSuite, GetRegistrarFromEmpty) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -241,9 +254,9 @@ TEST(PSJson, GetRegistrarFromEmpty) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, GetDomainFromEmpty) +TEST(PersistentStorageJsonTestSuite, GetDomainFromEmpty) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -254,7 +267,7 @@ TEST(PSJson, GetDomainFromEmpty) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, GetNetworkFromEmpty) +TEST(PersistentStorageJsonTestSuite, GetNetworkFromEmpty) { PersistentStorageJson psj(""); @@ -267,9 +280,9 @@ TEST(PSJson, GetNetworkFromEmpty) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, GetBorderRouterFromEmpty) +TEST(PersistentStorageJsonTestSuite, GetBorderRouterFromEmpty) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -280,12 +293,12 @@ TEST(PSJson, GetBorderRouterFromEmpty) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, GetRegistrarNotEmpty) +TEST(PersistentStorageJsonTestSuite, GetRegistrarNotEmpty) { // Make test independent - unlink("./test.tmp"); + unlink("./tmp/test.tmp"); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -310,12 +323,12 @@ TEST(PSJson, GetRegistrarNotEmpty) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, GetDomainNotEmpty) +TEST(PersistentStorageJsonTestSuite, GetDomainNotEmpty) { // Make test independent - unlink("./test.tmp"); + unlink("./tmp/test.tmp"); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -338,9 +351,9 @@ TEST(PSJson, GetDomainNotEmpty) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, GetNetworkNotEmpty) +TEST(PersistentStorageJsonTestSuite, GetNetworkNotEmpty) { - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -367,12 +380,12 @@ TEST(PSJson, GetNetworkNotEmpty) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, GetBorderRouterNotEmpty) +TEST(PersistentStorageJsonTestSuite, GetBorderRouterNotEmpty) { // Make the test independent - unlink("./test.tmp"); + unlink("./tmp/test.tmp"); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -412,12 +425,12 @@ TEST(PSJson, GetBorderRouterNotEmpty) } // UPD -TEST(PSJson, UpdRegistrar) +TEST(PersistentStorageJsonTestSuite, UpdRegistrar) { // Make the test independent - unlink("./test.tmp"); + unlink("./tmp/test.tmp"); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -446,12 +459,12 @@ TEST(PSJson, UpdRegistrar) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, UpdDomain) +TEST(PersistentStorageJsonTestSuite, UpdDomain) { // Make the test independent - unlink("./test.tmp"); + unlink("./tmp/test.tmp"); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -478,10 +491,10 @@ TEST(PSJson, UpdDomain) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, UpdNetwork) +TEST(PersistentStorageJsonTestSuite, UpdNetwork) { - unlink("./tmp.json"); - PersistentStorageJson psj("./tmp.json"); + unlink("./tmp/tmp.json"); + PersistentStorageJson psj("./tmp/tmp.json"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -505,12 +518,12 @@ TEST(PSJson, UpdNetwork) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, UpdBorderRouter) +TEST(PersistentStorageJsonTestSuite, UpdBorderRouter) { // Make test independent - unlink("./test.tmp"); + unlink("./tmp/test.tmp"); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -558,12 +571,12 @@ TEST(PSJson, UpdBorderRouter) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, LookupRegistrar) +TEST(PersistentStorageJsonTestSuite, LookupRegistrar) { // Make test independent - unlink("./test.tmp"); + unlink("./tmp/test.tmp"); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); @@ -634,12 +647,12 @@ TEST(PSJson, LookupRegistrar) EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); } -TEST(PSJson, LookupNetwork) +TEST(PersistentStorageJsonTestSuite, LookupNetwork) { // Make test independent - unlink("./test.tmp"); + unlink("./tmp/test.tmp"); - PersistentStorageJson psj("./test.tmp"); + PersistentStorageJson psj("./tmp/test.tmp"); EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); diff --git a/src/app/ps/registry_test.cpp b/src/app/ps/registry_test.cpp index 1c0ad96e..4b8a2bc7 100644 --- a/src/app/ps/registry_test.cpp +++ b/src/app/ps/registry_test.cpp @@ -32,21 +32,17 @@ */ #include - -#include "registry.hpp" - -#include - #include #include "app/cli/console.hpp" +#include "app/ps/registry.hpp" #define INFO(str) Console::Write(str) using namespace ot::commissioner::persistent_storage; using namespace ot::commissioner; -const char json_path[] = "./registry_test.json"; +const char json_path[] = "./tmp/registry_test.json"; TEST(RegJson, CreateEmptyRegistry) { From 57bd5f1e04d502eb2ed6e980ae2c5f9d3f04e1e1 Mon Sep 17 00:00:00 2001 From: Kangping Date: Thu, 9 May 2024 02:25:00 +0800 Subject: [PATCH 05/13] [api] remove the `XpanId` and `PanId` structs (#264) It's an overkill to define a dedicated class/struct for a simple `uint16_t` just for pretty print to json in HEX string. --- include/commissioner/error.hpp | 11 +- include/commissioner/network_data.hpp | 56 +------ src/app/cli/interpreter.cpp | 87 +++++------ src/app/cli/interpreter.hpp | 4 +- src/app/cli/interpreter_test.cpp | 155 +++++++++----------- src/app/cli/job.cpp | 6 +- src/app/cli/job.hpp | 2 +- src/app/cli/job_manager.cpp | 64 ++++---- src/app/cli/job_manager.hpp | 23 ++- src/app/cli/job_manager_test.cpp | 54 +++---- src/app/commissioner_app.cpp | 8 +- src/app/commissioner_app.hpp | 4 +- src/app/commissioner_app_dummy.cpp | 4 +- src/app/commissioner_app_mock.hpp | 4 +- src/app/json.cpp | 89 +++++------ src/app/ps/CMakeLists.txt | 6 + src/app/ps/persistent_storage_json.cpp | 10 +- src/app/ps/persistent_storage_json_test.cpp | 35 ++--- src/app/ps/registry.cpp | 66 +++++---- src/app/ps/registry.hpp | 16 +- src/app/ps/registry_entries.cpp | 29 ++-- src/app/ps/registry_entries.hpp | 14 +- src/app/ps/registry_test.cpp | 10 +- src/common/error.cpp | 2 +- src/common/utils.hpp | 28 ++++ src/common/utils_test.cpp | 23 +++ src/java/commissioner.i | 8 +- src/library/commissioner_impl.cpp | 6 +- src/library/network_data.cpp | 117 --------------- tests/integration/test_domain_syntax.sh | 26 ++-- 30 files changed, 415 insertions(+), 552 deletions(-) diff --git a/include/commissioner/error.hpp b/include/commissioner/error.hpp index 5771eed5..9b5dba76 100644 --- a/include/commissioner/error.hpp +++ b/include/commissioner/error.hpp @@ -264,14 +264,21 @@ inline bool operator!=(const ErrorCode &aErrorCode, const Error &aError) return !(aErrorCode == aError); } +std::string ErrorCodeToString(ErrorCode code); + /** * Allows pretty-print in unit tests. * * See https://google.github.io/googletest/advanced.html#teaching-googletest-how-to-print-your-values */ -inline void PrintTo(const Error &error, std::ostream *os) +inline void PrintTo(const Error &aError, std::ostream *os) +{ + *os << aError.ToString(); +} + +inline void PrintTo(ErrorCode aErrorCode, std::ostream *os) { - *os << error.ToString(); + *os << ErrorCodeToString(aErrorCode); } } // namespace commissioner diff --git a/include/commissioner/network_data.hpp b/include/commissioner/network_data.hpp index fb488b6a..bd496257 100644 --- a/include/commissioner/network_data.hpp +++ b/include/commissioner/network_data.hpp @@ -52,36 +52,6 @@ static constexpr uint8_t kMlrStatusNoResources = 4; static constexpr uint8_t kMlrStatusNotPrimary = 5; static constexpr uint8_t kMlrStatusFailure = 6; -/** - * Extended PAN Id wrapper - */ -struct XpanId -{ - static constexpr uint64_t kEmptyXpanId = 0; - - uint64_t mValue; - - XpanId(uint64_t val); - - XpanId(); - - std::string str() const; - - bool operator==(const XpanId &aOther) const; - - bool operator!=(const XpanId &aOther) const; - bool operator<(const XpanId &aOther) const; - - explicit operator std::string() const; - - /** - * Decodes hexadecimal string. - */ - Error FromHex(const std::string &aInput); -}; - -typedef std::vector XpanIdArray; - /** * @brief The Commissioner Dataset of the Thread Network Data. * @@ -249,26 +219,6 @@ enum SecurityPolicyFlags kSecurityPolicyMask_VR = 1 << 5 | 1 << 6 | 1 << 7, /// Protocol version }; -/** - * A PAN identifier. - */ -struct PanId -{ - static constexpr uint64_t kEmptyPanId = 0; - - uint16_t mValue; - explicit PanId(uint16_t aValue); - PanId(const PanId &aOther) = default; - PanId(); - - PanId &operator=(const PanId &aValue) = default; - PanId &operator=(uint16_t aValue); - explicit operator uint16_t() const; - explicit operator std::string() const; - - Error FromHex(const std::string &aInput); -}; - /** * @brief The Active Operational Dataset of the Thread Network Data. * @@ -283,13 +233,13 @@ struct PanId struct ActiveOperationalDataset { Timestamp mActiveTimestamp; + ByteArray mExtendedPanId; + uint16_t mPanId; + std::string mNetworkName; Channel mChannel; ChannelMask mChannelMask; - XpanId mExtendedPanId; ByteArray mMeshLocalPrefix; ByteArray mNetworkMasterKey; - std::string mNetworkName; - PanId mPanId; ByteArray mPSKc; SecurityPolicy mSecurityPolicy; diff --git a/src/app/cli/interpreter.cpp b/src/app/cli/interpreter.cpp index b8112487..e0549f81 100644 --- a/src/app/cli/interpreter.cpp +++ b/src/app/cli/interpreter.cpp @@ -123,6 +123,8 @@ namespace ot { namespace commissioner { using ot::commissioner::persistent_storage::Network; +using ot::commissioner::utils::Hex; +using ot::commissioner::utils::ParseInteger; namespace { /** @@ -177,10 +179,9 @@ Interpreter::NetworkSelectionComparator::~NetworkSelectionComparator() Network nwk; RegistryStatus status = mInterpreter.mRegistry->GetCurrentNetwork(nwk); - if (status == RegistryStatus::kSuccess && mStartWith.mValue != nwk.mXpan.mValue) + if (status == RegistryStatus::kSuccess && mStartWith != nwk.mXpan) { - Console::Write(nwk.mXpan.mValue == XpanId::kEmptyXpanId ? WARN_NETWORK_SELECTION_DROPPED - : WARN_NETWORK_SELECTION_CHANGED, + Console::Write(nwk.mXpan == 0 ? WARN_NETWORK_SELECTION_DROPPED : WARN_NETWORK_SELECTION_CHANGED, Console::Color::kYellow); } } @@ -351,23 +352,6 @@ template static std::string ToHex(T aInteger) return "0x" + utils::Hex(utils::Encode(aInteger)); }; -template static Error ParseInteger(T &aInteger, const std::string &aStr) -{ - Error error; - uint64_t integer; - char *endPtr = nullptr; - - integer = strtoull(aStr.c_str(), &endPtr, 0); - - VerifyOrExit(endPtr != nullptr && endPtr > aStr.c_str(), - error = ERROR_INVALID_ARGS("{} is not a valid integer", aStr)); - - aInteger = integer; - -exit: - return error; -} - static inline std::string ToLower(const std::string &aStr) { return utils::ToLower(aStr); @@ -404,11 +388,11 @@ Error Interpreter::UpdateNetworkSelectionInfo(bool onStart /*=false*/) VerifyOrExit(mRegistry->GetCurrentNetwork(nwk) == Registry::Status::kSuccess, error = ERROR_REGISTRY_ERROR(RUNTIME_CUR_NETWORK_FAILED)); - if (onStart && nwk.mXpan.mValue != XpanId::kEmptyXpanId) + if (onStart && nwk.mXpan != 0) { Console::Write(fmt::format(FMT_STRING("Network selection recalled from previous session.\n" "Restored to [{}:'{}']"), - nwk.mXpan.str(), nwk.mName), + utils::Hex(nwk.mXpan), nwk.mName), Console::Color::kGreen); } exit: @@ -549,7 +533,7 @@ Interpreter::Value Interpreter::Eval(const Expression &aExpr) if (mContext.mNwkAliases.size() > 0 || mContext.mDomAliases.size() > 0) { - XpanIdArray nids; + std::vector nids; SuccessOrExit(value = ValidateMultiNetworkSyntax(retExpr, nids)); if (IsMultiJob(retExpr)) // asynchronous processing required @@ -574,19 +558,19 @@ Interpreter::Value Interpreter::Eval(const Expression &aExpr) // handle single command using selected network if (mContext.mImportFiles.size() > 0) { - XpanId xpan = XpanId(); + uint64_t xpan = 0; if (mContext.mNwkAliases.empty()) { auto result = mRegistry->GetCurrentNetworkXpan(xpan); if (result != Registry::Status::kSuccess) { - xpan = XpanId(); + xpan = 0; } } else { - XpanIdArray nwks; - StringArray unresolved; + std::vector nwks; + StringArray unresolved; VerifyOrExit(mRegistry->GetNetworkXpansByAliases(mContext.mNwkAliases, nwks, unresolved) == Registry::Status::kSuccess, value = ERROR_INVALID_ARGS("Failed to resolve network alias for import")); @@ -624,7 +608,7 @@ bool Interpreter::IsInactiveCommissionerAllowed(const Expression &aExpr) return IsFeatureSupported(mInactiveCommissionerExecution, aExpr); } -Interpreter::Value Interpreter::ValidateMultiNetworkSyntax(const Expression &aExpr, XpanIdArray &aNids) +Interpreter::Value Interpreter::ValidateMultiNetworkSyntax(const Expression &aExpr, std::vector &aNids) { Error error; bool supported; @@ -846,7 +830,7 @@ void Interpreter::PrintOrExport(const Value &aValue) void Interpreter::PrintNetworkMessage(uint64_t aNid, std::string aMessage, Console::Color aColor) { - std::string nidHex = std::string(XpanId(aNid)); + std::string nidHex = utils::Hex(aNid); PrintNetworkMessage(nidHex, aMessage, aColor); } @@ -970,7 +954,7 @@ Interpreter::Value Interpreter::ProcessStart(const Expression &aExpr) case 1: { // starting currently selected network - XpanId nid; + uint64_t nid; RegistryStatus status = mRegistry->GetCurrentNetworkXpan(nid); VerifyOrExit(status == RegistryStatus::kSuccess, value = ERROR_REGISTRY_ERROR("getting selected network failed")); @@ -1191,7 +1175,7 @@ Interpreter::Value Interpreter::ProcessBr(const Expression &aExpr) } else { - PrintNetworkMessage(nwk.mXpan.mValue, RUNTIME_LOOKUP_FAILED, COLOR_ALIAS_FAILED); + PrintNetworkMessage(nwk.mXpan, RUNTIME_LOOKUP_FAILED, COLOR_ALIAS_FAILED); } } } @@ -1547,8 +1531,8 @@ Interpreter::Value Interpreter::ProcessBr(const Expression &aExpr) ExitNow(value = ERROR_CANCELLED("Scan cancelled by user")); } - XpanIdArray xpans; - StringArray unresolved; + std::vector xpans; + StringArray unresolved; if (!mContext.mNwkAliases.empty()) { VerifyOrExit(mRegistry->GetNetworkXpansByAliases(mContext.mNwkAliases, xpans, unresolved) == @@ -1580,8 +1564,7 @@ Interpreter::Value Interpreter::ProcessBr(const Expression &aExpr) (agentOrError.mBorderAgent.mDomainName == mContext.mDomAliases[0])) || (!mContext.mNwkAliases.empty() && (agentOrError.mBorderAgent.mPresentFlags & BorderAgent::kExtendedPanIdBit) && - (std::find(xpans.begin(), xpans.end(), XpanId(agentOrError.mBorderAgent.mExtendedPanId)) != - xpans.end()))) + (std::find(xpans.begin(), xpans.end(), agentOrError.mBorderAgent.mExtendedPanId) != xpans.end()))) { baJson.push_back(ba); } @@ -1686,9 +1669,9 @@ Interpreter::Value Interpreter::ProcessNetwork(const Expression &aExpr) } else { - StringArray aliases = {aExpr[2]}; - XpanIdArray xpans; - StringArray unresolved; + StringArray aliases = {aExpr[2]}; + std::vector xpans; + StringArray unresolved; VerifyOrExit(mRegistry->GetNetworkXpansByAliases(aliases, xpans, unresolved) == RegistryStatus::kSuccess, value = ERROR_REGISTRY_ERROR("Failed to resolve extended PAN Id for network '{}'", aExpr[2])); VerifyOrExit(xpans.size() == 1, value = ERROR_IO_ERROR("Detected {} networks instead of 1 for alias '{}'", @@ -1721,8 +1704,8 @@ Interpreter::Value Interpreter::ProcessNetwork(const Expression &aExpr) nwkData += '/'; } nwkData += nwk.mName; - json[nwk.mXpan.str()] = nwkData; - value = json.dump(JSON_INDENT_DEFAULT); + json[utils::Hex(nwk.mXpan)] = nwkData; + value = json.dump(JSON_INDENT_DEFAULT); } } else @@ -2115,7 +2098,7 @@ Interpreter::Value Interpreter::ProcessOpDatasetJob(CommissionerAppPtr &aCommiss } else if (CaseInsensitiveEqual(aExpr[2], "panid")) { - PanId panid; + uint16_t panid; if (isSet) { uint32_t delay; @@ -2127,7 +2110,7 @@ Interpreter::Value Interpreter::ProcessOpDatasetJob(CommissionerAppPtr &aCommiss else { SuccessOrExit(value = aCommissioner->GetPanId(panid)); - value = std::string(panid); + value = Hex(panid); } } else if (CaseInsensitiveEqual(aExpr[2], "pskc")) @@ -2166,7 +2149,7 @@ Interpreter::Value Interpreter::ProcessOpDatasetJob(CommissionerAppPtr &aCommiss ActiveOperationalDataset dataset; StringArray nwkAliases; StringArray unresolved; - XpanIdArray xpans; + std::vector xpans; if (isSet) { @@ -2186,13 +2169,13 @@ Interpreter::Value Interpreter::ProcessOpDatasetJob(CommissionerAppPtr &aCommiss // Get network object for the opdataset object if ((dataset.mPresentFlags & ActiveOperationalDataset::kExtendedPanIdBit) != 0) { - xpans.push_back(dataset.mExtendedPanId); + xpans.push_back(utils::Decode(dataset.mExtendedPanId)); } else { if ((dataset.mPresentFlags & ActiveOperationalDataset::kPanIdBit) != 0) { - nwkAliases.push_back(fmt::format(FMT_STRING("0x{:04X}"), dataset.mPanId.mValue)); + nwkAliases.push_back(Hex(dataset.mPanId)); } else if ((dataset.mPresentFlags & ActiveOperationalDataset::kNetworkNameBit) != 0) { @@ -2214,8 +2197,9 @@ Interpreter::Value Interpreter::ProcessOpDatasetJob(CommissionerAppPtr &aCommiss } if (mRegistry->GetNetworkByXpan(xpans[0], nwk) != RegistryStatus::kSuccess) { - Console::Write(fmt::format(FMT_STRING("Failed to find network record by XPAN '{}'"), xpans[0].str()), - Console::Color::kYellow); + Console::Write( + fmt::format(FMT_STRING("Failed to find network record by XPAN '{}'"), utils::Hex(xpans[0])), + Console::Color::kYellow); break; /// @todo It is possible that network XPAN ID /// might have change since the last sync /// so maybe it is worth to look up for @@ -2227,13 +2211,14 @@ Interpreter::Value Interpreter::ProcessOpDatasetJob(CommissionerAppPtr &aCommiss #define AODS_FIELD_IF_IS_SET(field, defaultValue) \ (((dataset.mPresentFlags & ActiveOperationalDataset::k##field##Bit) == 0) ? (defaultValue) : (dataset.m##field)) - nwk.mName = AODS_FIELD_IF_IS_SET(NetworkName, ""); - nwk.mXpan = AODS_FIELD_IF_IS_SET(ExtendedPanId, XpanId{}); + nwk.mName = AODS_FIELD_IF_IS_SET(NetworkName, ""); + nwk.mXpan = + utils::Decode(AODS_FIELD_IF_IS_SET(ExtendedPanId, ByteArray(kExtendedPanIdLength, 0))); nwk.mChannel = AODS_FIELD_IF_IS_SET(Channel, (Channel{0, 0})).mNumber; - nwk.mPan = AODS_FIELD_IF_IS_SET(PanId, PanId{}); + nwk.mPan = AODS_FIELD_IF_IS_SET(PanId, 0); if ((dataset.mPresentFlags & ActiveOperationalDataset::kPanIdBit) == 0) { - nwk.mPan = PanId::kEmptyPanId; + nwk.mPan = 0; } else { diff --git a/src/app/cli/interpreter.hpp b/src/app/cli/interpreter.hpp index 5cd2f816..c4e0d690 100644 --- a/src/app/cli/interpreter.hpp +++ b/src/app/cli/interpreter.hpp @@ -84,7 +84,7 @@ class Interpreter struct NetworkSelectionComparator { const Interpreter &mInterpreter; - XpanId mStartWith; + uint64_t mStartWith; bool mSuccess; NetworkSelectionComparator(const Interpreter &aInterpreter); @@ -179,7 +179,7 @@ class Interpreter * resolution of the provided network aliases is checked in the * course of execution. */ - Value ValidateMultiNetworkSyntax(const Expression &aExpr, XpanIdArray &aNids); + Value ValidateMultiNetworkSyntax(const Expression &aExpr, std::vector &aNids); /** * Resolves network aliases into a set of network ids. In the * course of resolution, duplicate network ids are compacted if diff --git a/src/app/cli/interpreter_test.cpp b/src/app/cli/interpreter_test.cpp index a01bc572..39602721 100644 --- a/src/app/cli/interpreter_test.cpp +++ b/src/app/cli/interpreter_test.cpp @@ -56,6 +56,7 @@ #include "commissioner/defines.hpp" #include "commissioner/error.hpp" #include "commissioner/network_data.hpp" +#include "common/utils.hpp" #include "fmt/core.h" #include "gmock/gmock-matchers.h" #include "gmock/gmock-spec-builders.h" @@ -63,6 +64,7 @@ #include "nlohmann/json.hpp" using namespace ot::commissioner; +using namespace ot::commissioner::utils; using namespace ot::commissioner::persistent_storage; using testing::_; @@ -152,7 +154,7 @@ TEST_F(InterpreterTestSuite, MNSV_ValidSyntaxPass) std::string command; Interpreter::Expression expr; Interpreter::Expression ret; - XpanIdArray nids; + std::vector nids; command = "start --nwk all"; expr = ctx.mInterpreter.ParseExpression(command); @@ -206,7 +208,7 @@ TEST_F(InterpreterTestSuite, MNSV_TwoGroupNwkAliasesFail) InitContext(ctx); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --nwk all other"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_FALSE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); @@ -225,7 +227,7 @@ TEST_F(InterpreterTestSuite, MNSV_ThisResolvesWithCurrentSet) ASSERT_EQ(ctx.mRegistry->SetCurrentNetwork(br), RegistryStatus::kSuccess); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --nwk this"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_TRUE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); @@ -241,7 +243,7 @@ TEST_F(InterpreterTestSuite, MNSV_ThisUnresolvesWithCurrentUnset) RegistryStatus::kSuccess); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --nwk this"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_FALSE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); @@ -265,12 +267,12 @@ TEST_F(InterpreterTestSuite, MNSV_AllOtherSameWithCurrentUnselected) // No current network selected Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --nwk all"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_TRUE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); - EXPECT_NE(std::find(nids.begin(), nids.end(), XpanId{1}), nids.end()); - EXPECT_NE(std::find(nids.begin(), nids.end(), XpanId{2}), nids.end()); + EXPECT_NE(std::find(nids.begin(), nids.end(), 1), nids.end()); + EXPECT_NE(std::find(nids.begin(), nids.end(), 2), nids.end()); ctx.mInterpreter.mContext.Cleanup(); ctx.mInterpreter.mJobManager->CleanupJobs(); ret.clear(); @@ -279,8 +281,8 @@ TEST_F(InterpreterTestSuite, MNSV_AllOtherSameWithCurrentUnselected) expr = ctx.mInterpreter.ParseExpression("start --nwk other"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_TRUE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); - EXPECT_NE(std::find(nids.begin(), nids.end(), XpanId{1}), nids.end()); - EXPECT_NE(std::find(nids.begin(), nids.end(), XpanId{2}), nids.end()); + EXPECT_NE(std::find(nids.begin(), nids.end(), 1), nids.end()); + EXPECT_NE(std::find(nids.begin(), nids.end(), 2), nids.end()); ctx.mInterpreter.mContext.Cleanup(); ctx.mInterpreter.mJobManager->CleanupJobs(); ret.clear(); @@ -306,12 +308,12 @@ TEST_F(InterpreterTestSuite, MNSV_AllOtherDifferWithCurrentSelected) ASSERT_EQ(ctx.mRegistry->SetCurrentNetwork(br), RegistryStatus::kSuccess); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --nwk all"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_TRUE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); - EXPECT_NE(std::find(nids.begin(), nids.end(), XpanId{1}), nids.end()); - EXPECT_NE(std::find(nids.begin(), nids.end(), XpanId{2}), nids.end()); + EXPECT_NE(std::find(nids.begin(), nids.end(), 1), nids.end()); + EXPECT_NE(std::find(nids.begin(), nids.end(), 2), nids.end()); ctx.mInterpreter.mContext.Cleanup(); ctx.mInterpreter.mJobManager->CleanupJobs(); ret.clear(); @@ -320,8 +322,8 @@ TEST_F(InterpreterTestSuite, MNSV_AllOtherDifferWithCurrentSelected) expr = ctx.mInterpreter.ParseExpression("start --nwk other"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_TRUE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); - EXPECT_EQ(std::find(nids.begin(), nids.end(), XpanId{1}), nids.end()); - EXPECT_NE(std::find(nids.begin(), nids.end(), XpanId{2}), nids.end()); + EXPECT_EQ(std::find(nids.begin(), nids.end(), 1), nids.end()); + EXPECT_NE(std::find(nids.begin(), nids.end(), 2), nids.end()); ctx.mInterpreter.mContext.Cleanup(); ctx.mInterpreter.mJobManager->CleanupJobs(); ret.clear(); @@ -344,7 +346,7 @@ TEST_F(InterpreterTestSuite, MNSV_TwoDomSwitchesFail) RegistryStatus::kSuccess); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --dom domain1 --dom domain2"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_FALSE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); @@ -361,7 +363,7 @@ TEST_F(InterpreterTestSuite, MNSV_UnexistingDomainResolveFails) RegistryStatus::kSuccess); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --dom domain2"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_FALSE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); @@ -383,12 +385,12 @@ TEST_F(InterpreterTestSuite, MNSV_ExistingDomainResolves) RegistryStatus::kSuccess); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --dom domain1"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_TRUE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); - EXPECT_NE(std::find(nids.begin(), nids.end(), XpanId{1}), nids.end()); - EXPECT_EQ(std::find(nids.begin(), nids.end(), XpanId{2}), nids.end()); + EXPECT_NE(std::find(nids.begin(), nids.end(), 1), nids.end()); + EXPECT_EQ(std::find(nids.begin(), nids.end(), 2), nids.end()); } TEST_F(InterpreterTestSuite, MNSV_AmbiguousNwkResolutionFails) @@ -397,9 +399,9 @@ TEST_F(InterpreterTestSuite, MNSV_AmbiguousNwkResolutionFails) InitContext(ctx); NetworkId nid; - ASSERT_EQ(ctx.mRegistry->mStorage->Add( - Network{NetworkId{EMPTY_ID}, DomainId{EMPTY_ID}, "net1", XpanId{1}, 0, 0xAB, "", 0}, nid), - PersistentStorage::Status::kSuccess); + ASSERT_EQ( + ctx.mRegistry->mStorage->Add(Network{NetworkId{EMPTY_ID}, DomainId{EMPTY_ID}, "net1", 1, 0, 0xAB, "", 0}, nid), + PersistentStorage::Status::kSuccess); ASSERT_EQ( ctx.mRegistry->Add(BorderAgent{"127.0.0.1", 20001, ByteArray{}, "1.1", BorderAgent::State{0, 0, 0, 0, 0}, "net1", 1, "", "", Timestamp{0, 0, 0}, 0, "", ByteArray{}, "domain1", 0, 0, "", @@ -408,18 +410,18 @@ TEST_F(InterpreterTestSuite, MNSV_AmbiguousNwkResolutionFails) // lookup by PAN ID must succeed Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --nwk ab"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_EQ(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).mError.GetCode(), ErrorCode::kNone); EXPECT_EQ(nids.size(), 1); - EXPECT_EQ(nids[0], XpanId{1}); + EXPECT_EQ(nids[0], 1); ctx.mInterpreter.mContext.Cleanup(); // create ambiguity by adding another network with the same PAN ID - ASSERT_EQ(ctx.mRegistry->mStorage->Add( - Network{NetworkId{EMPTY_ID}, DomainId{EMPTY_ID}, "net2", XpanId{2}, 0, 0xAB, "", 0}, nid), - PersistentStorage::Status::kSuccess); + ASSERT_EQ( + ctx.mRegistry->mStorage->Add(Network{NetworkId{EMPTY_ID}, DomainId{EMPTY_ID}, "net2", 2, 0, 0xAB, "", 0}, nid), + PersistentStorage::Status::kSuccess); ASSERT_EQ( ctx.mRegistry->Add(BorderAgent{"127.0.0.2", 20001, ByteArray{}, "1.1", BorderAgent::State{0, 0, 0, 0, 0}, "net2", 2, "", "", Timestamp{0, 0, 0}, 0, "", ByteArray{}, "domain2", 0, 0, "", @@ -448,7 +450,7 @@ TEST_F(InterpreterTestSuite, MNSV_SameResolutionFromTwoAliasesCollapses) RegistryStatus::kSuccess); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --nwk 1 net1"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_TRUE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); @@ -471,7 +473,7 @@ TEST_F(InterpreterTestSuite, MNSV_GroupAndIndividualNwkAliasesMustFail) RegistryStatus::kSuccess); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --nwk 1 all"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_FALSE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); @@ -496,12 +498,12 @@ TEST_F(InterpreterTestSuite, MNSV_DomThisResolvesWithRespectToSelection) ASSERT_EQ(ctx.mRegistry->SetCurrentNetwork(br), RegistryStatus::kSuccess); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start --dom this"); EXPECT_EQ(ctx.mInterpreter.ReParseMultiNetworkSyntax(expr, ret).GetCode(), ErrorCode::kNone); EXPECT_TRUE(ctx.mInterpreter.ValidateMultiNetworkSyntax(ret, nids).HasNoError()); EXPECT_EQ(nids.size(), 1); - EXPECT_EQ(nids[0], XpanId{1}); + EXPECT_EQ(nids[0], 1); } TEST_F(InterpreterTestSuite, MNSV_NoAliasesResolvesToThisNwk) @@ -531,12 +533,12 @@ TEST_F(InterpreterTestSuite, MNSV_NoAliasesResolvesToThisNwk) BorderRouter br; br.mNetworkId = NetworkId{2}; ASSERT_EQ(ctx.mRegistry->SetCurrentNetwork(br), RegistryStatus::kSuccess); - XpanId nid; + uint64_t nid; ASSERT_EQ(ctx.mRegistry->GetCurrentNetworkXpan(nid), RegistryStatus::kSuccess); - ASSERT_EQ(nid, XpanId{3}); + ASSERT_EQ(nid, 3); Interpreter::Expression expr, ret; - XpanIdArray nids; + std::vector nids; expr = ctx.mInterpreter.ParseExpression("start"); CommissionerAppMockPtr pcaMock{new CommissionerAppMock()}; @@ -1133,17 +1135,17 @@ TEST_F(InterpreterTestSuite, PC_TokenWithCCM) InitContext(ctx); // prepare CCM network record - const std::string kDomainName = "domain1"; - const std::string kNetworkName = "net1"; - const std::string kSmPath = "./tmp/dom/" + kDomainName + "/"; - XpanId xpanCcm{1}; + const std::string kDomainName = "domain1"; + const std::string kNetworkName = "net1"; + const std::string kSmPath = "./tmp/dom/" + kDomainName + "/"; + uint64_t xpanCcm = 1; + BorderAgent::State baStateCcm{BorderAgent::State::ConnectionMode::kX509Connection, 0, 0, 0, 0}; - ASSERT_EQ( - ctx.mRegistry->Add(BorderAgent{"127.0.0.1", 20001, ByteArray{}, "1.1", baStateCcm, kNetworkName, xpanCcm.mValue, - "", "", Timestamp{0, 0, 0}, 0, "", ByteArray{}, kDomainName, 0, 0, "", 0, - 0x1F | BorderAgent::kDomainNameBit | BorderAgent::kExtendedPanIdBit}), - RegistryStatus::kSuccess); + ASSERT_EQ(ctx.mRegistry->Add(BorderAgent{"127.0.0.1", 20001, ByteArray{}, "1.1", baStateCcm, kNetworkName, xpanCcm, + "", "", Timestamp{0, 0, 0}, 0, "", ByteArray{}, kDomainName, 0, 0, "", 0, + 0x1F | BorderAgent::kDomainNameBit | BorderAgent::kExtendedPanIdBit}), + RegistryStatus::kSuccess); // prepare fake SM for the CCM network std::vector> smFiles = {{"ca", kSmPath + "ca.pem"}, @@ -1189,17 +1191,18 @@ TEST_F(InterpreterTestSuite, PC_TokenWithNonCCM) InitContext(ctx); // prepare non-CCM network record - const std::string kDomainName = "DefaultDomain"; - const std::string kNetworkName = "net2"; - const std::string kSmPath = "./tmp/nwk/" + kNetworkName + "/"; - XpanId xpanNonCcm{2}; + const std::string kDomainName = "DefaultDomain"; + const std::string kNetworkName = "net2"; + const std::string kSmPath = "./tmp/nwk/" + kNetworkName + "/"; + uint64_t xpanNonCcm = 2; + BorderAgent::State baStateNonCcm{BorderAgent::State::ConnectionMode::kPSKcConnection, 0, 0, 0, 0}; - ASSERT_EQ(ctx.mRegistry->Add(BorderAgent{"127.0.0.1", 20001, ByteArray{}, "1.1", baStateNonCcm, kNetworkName, - xpanNonCcm.mValue, "", "", Timestamp{0, 0, 0}, 0, "", ByteArray{}, - kDomainName, 0, 0, "", 0, - 0x1F | BorderAgent::kDomainNameBit | BorderAgent::kExtendedPanIdBit}), - RegistryStatus::kSuccess); + ASSERT_EQ( + ctx.mRegistry->Add(BorderAgent{"127.0.0.1", 20001, ByteArray{}, "1.1", baStateNonCcm, kNetworkName, xpanNonCcm, + "", "", Timestamp{0, 0, 0}, 0, "", ByteArray{}, kDomainName, 0, 0, "", 0, + 0x1F | BorderAgent::kDomainNameBit | BorderAgent::kExtendedPanIdBit}), + RegistryStatus::kSuccess); // prepare fake SM for the non-CCM network std::vector> smFiles = { {"ca", kSmPath + "ca.pem"}, {"key", kSmPath + "priv.pem"}, {"cert", kSmPath + "cert.pem"}}; @@ -1505,8 +1508,8 @@ TEST_F(InterpreterTestSuite, PC_NetworkIdentifyWithDomain) { EXPECT_TRUE(false) << "Failed to parse value: " << e.what(); } - EXPECT_TRUE(json.contains("0000000000000001")); - EXPECT_STREQ("domain1/net1", json.at("0000000000000001").get().c_str()); + EXPECT_TRUE(json.contains("0x0000000000000001")); + EXPECT_STREQ("domain1/net1", json.at("0x0000000000000001").get().c_str()); } TEST_F(InterpreterTestSuite, PC_NetworkIdentifyWithoutDomain) @@ -1546,8 +1549,8 @@ TEST_F(InterpreterTestSuite, PC_NetworkIdentifyWithoutDomain) { EXPECT_TRUE(false) << "Failed to parse value: " << e.what(); } - EXPECT_TRUE(json.contains("0000000000000002")); - EXPECT_STREQ("net2", json.at("0000000000000002").get().c_str()); + EXPECT_TRUE(json.contains("0x0000000000000002")); + EXPECT_STREQ("net2", json.at("0x0000000000000002").get().c_str()); } TEST_F(InterpreterTestSuite, PC_NetworkIdentifyUnset) @@ -1804,16 +1807,17 @@ TEST_F(InterpreterTestSuite, PC_OpdatasetGetActive) InitContext(ctx); NetworkId nwk_id; - EXPECT_EQ(ctx.mRegistry->mStorage->Add(Network{EMPTY_ID, EMPTY_ID, "", XpanId{1}, 0, 0, "", 0}, nwk_id), + EXPECT_EQ(ctx.mRegistry->mStorage->Add(Network{EMPTY_ID, EMPTY_ID, "", 1, 0, 0, "", 0}, nwk_id), PersistentStorage::Status::kSuccess); Network nwk; EXPECT_EQ(ctx.mRegistry->mStorage->Get(nwk_id, nwk), PersistentStorage::Status::kSuccess); - EXPECT_EQ((std::string)nwk.mPan, "0x0000"); + EXPECT_EQ(utils::Hex(nwk.mPan), "0x0000"); EXPECT_CALL(*ctx.mDefaultCommissionerObject, GetActiveDataset(_, _)) .Times(2) .WillRepeatedly(DoAll(WithArg<0>([](ActiveOperationalDataset &a) { - a.mExtendedPanId = XpanId{1}, a.mPanId = 1; + a.mExtendedPanId = ByteArray{0, 0, 0, 0, 0, 0, 0, 1}; + a.mPanId = 1; a.mPresentFlags = ActiveOperationalDataset::kPanIdBit | ActiveOperationalDataset::kExtendedPanIdBit; }), @@ -1827,7 +1831,7 @@ TEST_F(InterpreterTestSuite, PC_OpdatasetGetActive) EXPECT_TRUE(value.HasNoError()); EXPECT_EQ(ctx.mRegistry->mStorage->Get(nwk_id, nwk), PersistentStorage::Status::kSuccess); - EXPECT_EQ(nwk.mPan.mValue, 0x0001); + EXPECT_EQ(nwk.mPan, 0x0001); expr = ctx.mInterpreter.ParseExpression("opdataset get active --export ./tmp/aods.json"); value = ctx.mInterpreter.Eval(expr); @@ -2369,24 +2373,13 @@ TEST_F(InterpreterTestSuite, PC_BrAddInterObjectInconsistencyFail) TEST_F(InterpreterTestSuite, PC_BrAdd) { -#define XPAN_1234 "1234" #define XPAN_1235 "0x1235" -#define XPAN_1236 "0000000000001236" -#define XPAN_1237 "00000000000001237" // length > 16 +#define XPAN_1236 "0x0000000000001236" TestContext ctx; InitContext(ctx); std::string brJson = "[\n\ - {\n\ - \"Addr\": \"1234::5678\",\n\ - \"Port\": 2000,\n\ - \"ThreadVersion\": \"th1.2\",\n\ - \"State\": 0,\n\ - \"NetworkName\": \"net1\",\n\ - \"ExtendedPanId\": \"" XPAN_1234 "\",\n\ - \"DomainName\": \"dom1\"\n\ - },\n\ {\n\ \"Addr\": \"1234::5679\",\n\ \"Port\": 2001,\n\ @@ -2426,28 +2419,24 @@ TEST_F(InterpreterTestSuite, PC_BrAdd) BorderRouterArray brs; EXPECT_EQ(ctx.mInterpreter.mRegistry->GetAllBorderRouters(brs), RegistryStatus::kSuccess); - EXPECT_EQ(brs.size(), 4); + EXPECT_EQ(brs.size(), 3); NetworkArray nwks; EXPECT_EQ(ctx.mInterpreter.mRegistry->GetAllNetworks(nwks), RegistryStatus::kSuccess); - EXPECT_EQ(nwks.size(), 3); + EXPECT_EQ(nwks.size(), 2); DomainArray doms; EXPECT_EQ(ctx.mInterpreter.mRegistry->GetAllDomains(doms), RegistryStatus::kSuccess); EXPECT_EQ(doms.size(), 2); - Network nwk; - XpanId xpan; - EXPECT_EQ(xpan.FromHex(XPAN_1234).GetCode(), ErrorCode::kNone); - EXPECT_EQ(ctx.mInterpreter.mRegistry->GetNetworkByXpan(0x1234, nwk), RegistryStatus::kSuccess); - EXPECT_EQ(nwk.mXpan, xpan); - EXPECT_EQ(xpan.FromHex(XPAN_1235).GetCode(), ErrorCode::kNone); + Network nwk; + uint64_t xpan; + EXPECT_EQ(utils::ParseInteger(xpan, "0x1235").GetCode(), ErrorCode::kNone); EXPECT_EQ(ctx.mInterpreter.mRegistry->GetNetworkByXpan(0x1235, nwk), RegistryStatus::kSuccess); EXPECT_EQ(nwk.mXpan, xpan); - EXPECT_EQ(xpan.FromHex(XPAN_1236).GetCode(), ErrorCode::kNone); + EXPECT_EQ(utils::ParseInteger(xpan, "0x0000000000001236").GetCode(), ErrorCode::kNone); EXPECT_EQ(ctx.mInterpreter.mRegistry->GetNetworkByXpan(0x1236, nwk), RegistryStatus::kSuccess); EXPECT_EQ(nwk.mXpan, xpan); - EXPECT_EQ(xpan.FromHex(XPAN_1237).GetCode(), ErrorCode::kBadFormat); } TEST_F(InterpreterTestSuite, PC_BrListPositive) @@ -2626,7 +2615,7 @@ TEST_F(InterpreterTestSuite, PC_BrDeleteExplicitSelectedFails) "", 0, 0x3F | BorderAgent::kDomainNameBit}), RegistryStatus::kSuccess); - EXPECT_EQ(ctx.mRegistry->SetCurrentNetwork(XpanId{2}), RegistryStatus::kSuccess); + EXPECT_EQ(ctx.mRegistry->SetCurrentNetwork(2), RegistryStatus::kSuccess); Interpreter::Expression expr; Interpreter::Value value; diff --git a/src/app/cli/job.cpp b/src/app/cli/job.cpp index 7535e3ea..6a38524a 100644 --- a/src/app/cli/job.cpp +++ b/src/app/cli/job.cpp @@ -54,7 +54,7 @@ void Job::Wait() mJobThread.join(); if (!mValue.HasNoError()) { - LOG_DEBUG(LOG_REGION_JOB, "{}: job '{}' failed: {}", XpanId(mXpanId).str(), GetCommandString(), + LOG_DEBUG(LOG_REGION_JOB, "{}: job '{}' failed: {}", utils::Hex(mXpanId), GetCommandString(), mValue.ToString()); } } @@ -79,12 +79,12 @@ Job::Job(Interpreter &aInterpreter, CommissionerAppPtr &aCommApp, Interpreter::Expression aExpr, Interpreter::JobEvaluator aEval, - XpanId aXpanId) + uint64_t aXpanId) : mInterpreter(aInterpreter) , mCommissioner(aCommApp) , mExpr(aExpr) , mEval(aEval) - , mXpanId(aXpanId.mValue) + , mXpanId(aXpanId) { } diff --git a/src/app/cli/job.hpp b/src/app/cli/job.hpp index b23cfb29..4ae1a250 100644 --- a/src/app/cli/job.hpp +++ b/src/app/cli/job.hpp @@ -52,7 +52,7 @@ class Job CommissionerAppPtr &aCommApp, Interpreter::Expression aExpr, Interpreter::JobEvaluator aEval, - XpanId aXpanId); + uint64_t aXpanId); ~Job() = default; void Run(); diff --git a/src/app/cli/job_manager.cpp b/src/app/cli/job_manager.cpp index f0beadd0..4d2d7e3f 100644 --- a/src/app/cli/job_manager.cpp +++ b/src/app/cli/job_manager.cpp @@ -117,7 +117,7 @@ void JobManager::SetImportFile(const std::string &importFile) mImportFile = importFile; } -Error JobManager::CreateJob(CommissionerAppPtr &aCommissioner, const Interpreter::Expression &aExpr, XpanId aXpanId) +Error JobManager::CreateJob(CommissionerAppPtr &aCommissioner, const Interpreter::Expression &aExpr, uint64_t aXpanId) { Interpreter::JobEvaluator eval; auto mapItem = Interpreter::mJobEvaluatorMap.find(utils::ToLower(aExpr[0])); @@ -133,7 +133,9 @@ Error JobManager::CreateJob(CommissionerAppPtr &aCommissioner, const Interpreter return ERROR_NONE; } -Error JobManager::PrepareJobs(const Interpreter::Expression &aExpr, const XpanIdArray &aNids, bool aGroupAlias) +Error JobManager::PrepareJobs(const Interpreter::Expression &aExpr, + const std::vector &aNids, + bool aGroupAlias) { Error error; @@ -191,7 +193,9 @@ Error JobManager::PrepareJobs(const Interpreter::Expression &aExpr, const XpanId return error; } -Error JobManager::PrepareStartJobs(const Interpreter::Expression &aExpr, const XpanIdArray &aNids, bool aGroupAlias) +Error JobManager::PrepareStartJobs(const Interpreter::Expression &aExpr, + const std::vector &aNids, + bool aGroupAlias) { Error error = ERROR_NONE; @@ -248,7 +252,9 @@ Error JobManager::PrepareStartJobs(const Interpreter::Expression &aExpr, const X return error; } -Error JobManager::PrepareStopJobs(const Interpreter::Expression &aExpr, const XpanIdArray &aNids, bool aGroupAlias) +Error JobManager::PrepareStopJobs(const Interpreter::Expression &aExpr, + const std::vector &aNids, + bool aGroupAlias) { Error error = ERROR_NONE; @@ -282,7 +288,7 @@ Error JobManager::PrepareStopJobs(const Interpreter::Expression &aExpr, const Xp return error; } -Error JobManager::PrepareDtlsConfig(const XpanId aNid, Config &aConfig) +Error JobManager::PrepareDtlsConfig(uint64_t aNid, Config &aConfig) { Error error; std::string domainName; @@ -321,12 +327,12 @@ Error JobManager::PrepareDtlsConfig(const XpanId aNid, Config &aConfig) status = mInterpreter.mRegistry->GetNetworkByXpan(aNid, nwk); VerifyOrExit(status == RegistryStatus::kSuccess, - error = ERROR_NOT_FOUND("network not found by XPAN '{}'", aNid.str())); + error = ERROR_NOT_FOUND("network not found by XPAN '{}'", utils::Hex(aNid))); isCCM = nwk.mCcm > 0; status = mInterpreter.mRegistry->GetDomainNameByXpan(aNid, domainName); if (status != RegistryStatus::kSuccess) { - LOG_DEBUG(LOG_REGION_JOB_MANAGER, "{}: domain resolution failed with status={}", XpanId(aNid).str(), + LOG_DEBUG(LOG_REGION_JOB_MANAGER, "{}: domain resolution failed with status={}", utils::Hex(aNid), static_cast(status)); } @@ -355,8 +361,8 @@ Error JobManager::PrepareDtlsConfig(const XpanId aNid, Config &aConfig) /// loading. Therefore, any other connection /// mode is considered a wrong configuration of /// border router, and respectively ignored. - LOG_DEBUG(LOG_REGION_JOB_MANAGER, "loading PSKc ignored for CCM network [{}:'{}']", aNid.str(), - nwk.mName); + LOG_DEBUG(LOG_REGION_JOB_MANAGER, "loading PSKc ignored for CCM network [{}:'{}']", + utils::Hex(aNid), nwk.mName); } goto update; } @@ -369,7 +375,7 @@ Error JobManager::PrepareDtlsConfig(const XpanId aNid, Config &aConfig) } } - error = security_material::GetNetworkSM(nwk.mXpan.str(), needCert, needPSKc, dtlsConfig); + error = security_material::GetNetworkSM(utils::Hex(nwk.mXpan), needCert, needPSKc, dtlsConfig); if (ERROR_NONE != error) { LOG_STR(DEBUG, LOG_REGION_JOB_MANAGER, error.GetMessage()); @@ -427,13 +433,13 @@ Error JobManager::PrepareDtlsConfig(const XpanId aNid, Config &aConfig) #undef UPDATE_IF_SET if (dtlsConfig.IsIncomplete(needCert, needPSKc, isCCM)) { - error = ERROR_SECURITY("incomplete DTLS configuration for the network [{}:'{}']", aNid.str(), nwk.mName); + error = ERROR_SECURITY("incomplete DTLS configuration for the network [{}:'{}']", utils::Hex(aNid), nwk.mName); } exit: return error; } -Error JobManager::MakeBorderRouterChoice(const XpanId aNid, BorderRouter &br) +Error JobManager::MakeBorderRouterChoice(uint64_t aNid, BorderRouter &br) { Error error; BRArray brs; @@ -451,7 +457,7 @@ Error JobManager::MakeBorderRouterChoice(const XpanId aNid, BorderRouter &br) } status = mInterpreter.mRegistry->GetNetworkByXpan(aNid, nwk); VerifyOrExit(status == RegistryStatus::kSuccess, - error = ERROR_NOT_FOUND("network not found by XPAN '{}'", aNid.str())); + error = ERROR_NOT_FOUND("network not found by XPAN '{}'", utils::Hex(aNid))); if (nwk.mCcm > 0) // Dealing with domain network { // - try to find active and connectable Primary BBR @@ -534,7 +540,7 @@ Error JobManager::MakeBorderRouterChoice(const XpanId aNid, BorderRouter &br) return error; } -Error JobManager::AppendImport(XpanId aXpanId, Interpreter::Expression &aExpr) +Error JobManager::AppendImport(uint64_t aXpanId, Interpreter::Expression &aExpr) { Error error; std::string jsonStr; @@ -543,13 +549,13 @@ Error JobManager::AppendImport(XpanId aXpanId, Interpreter::Expression &aExpr) SuccessOrExit(error = JsonFromFile(jsonStr, mImportFile)); jsonSrc = Json::parse(jsonStr); - if (aXpanId == XpanId()) // must be single command + if (aXpanId == 0) // must be single command { json = jsonSrc; } - else if (jsonSrc.count(aXpanId.str()) > 0) + else if (jsonSrc.count(utils::Hex(aXpanId)) > 0) { - json = jsonSrc[aXpanId.str()]; + json = jsonSrc[utils::Hex(aXpanId)]; } jsonStr = json.dump(JSON_INDENT_DEFAULT); if (utils::ToLower(aExpr[0]) == "opdataset") @@ -667,14 +673,14 @@ Interpreter::Value JobManager::CollectJobsValue() { Interpreter::Value value; nlohmann::json json; - XpanId xpan; + uint64_t xpan; for (const auto &job : mJobPool) { ASSERT(job->IsStopped()); if (job->GetValue().HasNoError()) { - xpan = XpanId{job->GetXpanId()}; + xpan = job->GetXpanId(); try { std::string valueStr = job->GetValue().ToString(); @@ -688,7 +694,7 @@ Interpreter::Value JobManager::CollectJobsValue() // nothing but [done] is printed; we need to see a // distinguished result per network } - json[xpan.str()] = nlohmann::json::parse(valueStr); + json[utils::Hex(xpan)] = nlohmann::json::parse(valueStr); } catch (std::exception &e) { ErrorMsg(xpan, e.what()); @@ -696,7 +702,7 @@ Interpreter::Value JobManager::CollectJobsValue() } else // produce error messages immediately before printing value { - ErrorMsg(XpanId{job->GetXpanId()}, job->GetValue().ToString()); + ErrorMsg(job->GetXpanId(), job->GetValue().ToString()); } } value = json.dump(JSON_INDENT_DEFAULT); @@ -719,13 +725,13 @@ void JobManager::StopCommissionerPool() Error JobManager::GetSelectedCommissioner(CommissionerAppPtr &aCommissioner) { Error error = ERROR_NONE; - XpanId nid; + uint64_t nid; RegistryStatus status; status = mInterpreter.mRegistry->GetCurrentNetworkXpan(nid); VerifyOrExit(RegistryStatus::kSuccess == status, error = ERROR_REGISTRY_ERROR("getting selected network failed")); - if (nid.mValue != XpanId::kEmptyXpanId) + if (nid != 0) { auto entry = mCommissionerPool.find(nid); if (entry != mCommissionerPool.end()) @@ -761,19 +767,19 @@ bool JobManager::IsClean() return mJobPool.size() == 0 && mImportFile.size() == 0; } -void JobManager::ErrorMsg(XpanId aNid, std::string aMessage) +void JobManager::ErrorMsg(uint64_t aNid, std::string aMessage) { - mInterpreter.PrintNetworkMessage(aNid.mValue, aMessage, Console::Color::kRed); + mInterpreter.PrintNetworkMessage(aNid, aMessage, Console::Color::kRed); } -void JobManager::WarningMsg(XpanId aNid, std::string aMessage) +void JobManager::WarningMsg(uint64_t aNid, std::string aMessage) { - mInterpreter.PrintNetworkMessage(aNid.mValue, aMessage, Console::Color::kMagenta); + mInterpreter.PrintNetworkMessage(aNid, aMessage, Console::Color::kMagenta); } -void JobManager::InfoMsg(XpanId aNid, std::string aMessage) +void JobManager::InfoMsg(uint64_t aNid, std::string aMessage) { - mInterpreter.PrintNetworkMessage(aNid.mValue, aMessage, Console::Color::kDefault); + mInterpreter.PrintNetworkMessage(aNid, aMessage, Console::Color::kDefault); } } // namespace commissioner diff --git a/src/app/cli/job_manager.hpp b/src/app/cli/job_manager.hpp index dae006b0..72143c3d 100644 --- a/src/app/cli/job_manager.hpp +++ b/src/app/cli/job_manager.hpp @@ -45,7 +45,6 @@ namespace commissioner { using CommissionerAppPtr = std::shared_ptr; using RegistryStatus = ot::commissioner::persistent_storage::Registry::Status; -using ot::commissioner::XpanId; using ot::commissioner::persistent_storage::BorderRouter; class JobManager @@ -61,7 +60,7 @@ class JobManager * * @see JobManager::CreateJob() */ - Error PrepareJobs(const Interpreter::Expression &aExpr, const XpanIdArray &aNids, bool aGroupAlias); + Error PrepareJobs(const Interpreter::Expression &aExpr, const std::vector &aNids, bool aGroupAlias); /** * Run all prepared jobs. * @@ -118,7 +117,7 @@ class JobManager * It is expected mImportFile contains a JSON object where the * imported part is a value of a map entry under aNid key. */ - Error AppendImport(XpanId aXpanId, Interpreter::Expression &aExpr); + Error AppendImport(uint64_t aXpanId, Interpreter::Expression &aExpr); /** * Make a well-thought choice from border routers belonging to a * given network identified by aNid XPAN ID. @@ -129,12 +128,12 @@ class JobManager * If in non-CCM mode, a BR with most highly avaliable and Thread-active * interface becomes the choice. */ - Error MakeBorderRouterChoice(const XpanId aNid, BorderRouter &br); + Error MakeBorderRouterChoice(uint64_t aNid, BorderRouter &br); private: friend class JobManagerTestSuite; - using CommissionerPool = std::map; + using CommissionerPool = std::map; using JobPool = std::vector; /** * Wait for all job threads to join. @@ -143,11 +142,11 @@ class JobManager /** * A flavor of JobManager::PrepareJobs() for `start' command specifically. */ - Error PrepareStartJobs(const Interpreter::Expression &aExpr, const XpanIdArray &aNids, bool aGroupAlias); + Error PrepareStartJobs(const Interpreter::Expression &aExpr, const std::vector &aNids, bool aGroupAlias); /** * A flavor of JobManager::PrepareJobs() for `stop' command specifically. */ - Error PrepareStopJobs(const Interpreter::Expression &aExpr, const XpanIdArray &aNids, bool aGroupAlias); + Error PrepareStopJobs(const Interpreter::Expression &aExpr, const std::vector &aNids, bool aGroupAlias); /** * Updates DTLS parts of Config for the given network. * @@ -173,15 +172,15 @@ class JobManager * connection must restart to adopt the most recent connection * information. */ - Error PrepareDtlsConfig(const XpanId aNid, Config &aConfig); + Error PrepareDtlsConfig(uint64_t aNid, Config &aConfig); /** * Creates @ref Job object and places the job into @ref JobManager::mJobPool. */ - Error CreateJob(CommissionerAppPtr &aCommissioner, const Interpreter::Expression &aExpr, XpanId aXpanId); + Error CreateJob(CommissionerAppPtr &aCommissioner, const Interpreter::Expression &aExpr, uint64_t aXpanId); - void ErrorMsg(XpanId aNid, std::string aMessage); - void WarningMsg(XpanId aNid, std::string aMessage); - void InfoMsg(XpanId aNid, std::string aMessage); + void ErrorMsg(uint64_t aNid, std::string aMessage); + void WarningMsg(uint64_t aNid, std::string aMessage); + void InfoMsg(uint64_t aNid, std::string aMessage); /** * Pool of @ref Job objects prepared per command execution. The diff --git a/src/app/cli/job_manager_test.cpp b/src/app/cli/job_manager_test.cpp index ad9705fd..8efacd41 100644 --- a/src/app/cli/job_manager_test.cpp +++ b/src/app/cli/job_manager_test.cpp @@ -627,9 +627,9 @@ TEST_F(JobManagerTestSuite, BuildFinalResultString) Interpreter::Value value = ctx.mJobManager.CollectJobsValue(); nlohmann::json json = nlohmann::json::parse(value.ToString()); - EXPECT_TRUE(json.contains(XpanId{1}.str())); - EXPECT_TRUE(json.contains(XpanId{2}.str())); - EXPECT_FALSE(json.contains(XpanId{3}.str())); + EXPECT_TRUE(json.contains("0x0000000000000001")); + EXPECT_TRUE(json.contains("0x0000000000000002")); + EXPECT_FALSE(json.contains("0x0000000000000003")); ctx.mJobManager.CleanupJobs(); // "active" command @@ -637,12 +637,12 @@ TEST_F(JobManagerTestSuite, BuildFinalResultString) ctx.mJobManager.RunJobs(); value = ctx.mJobManager.CollectJobsValue(); json = nlohmann::json::parse(value.ToString()); - EXPECT_TRUE(json.contains(XpanId{1}.str())); - EXPECT_TRUE(json.contains(XpanId{2}.str())); - EXPECT_TRUE(json.contains(XpanId{3}.str())); - EXPECT_TRUE(json[XpanId{1}.str()]); - EXPECT_TRUE(json[XpanId{2}.str()]); - EXPECT_FALSE(json[XpanId{3}.str()]); + EXPECT_TRUE(json.contains("0x0000000000000001")); + EXPECT_TRUE(json.contains("0x0000000000000002")); + EXPECT_TRUE(json.contains("0x0000000000000003")); + EXPECT_TRUE(json["0x0000000000000001"]); + EXPECT_TRUE(json["0x0000000000000002"]); + EXPECT_FALSE(json["0x0000000000000003"]); ctx.mJobManager.CleanupJobs(); // "sessionid" command @@ -654,10 +654,10 @@ TEST_F(JobManagerTestSuite, BuildFinalResultString) ctx.mJobManager.RunJobs(); value = ctx.mJobManager.CollectJobsValue(); json = nlohmann::json::parse(value.ToString()); - EXPECT_TRUE(json.contains(XpanId{1}.str())); - EXPECT_TRUE(json.contains(XpanId{2}.str())); - EXPECT_EQ(json[XpanId{1}.str()], 0); - EXPECT_EQ(json[XpanId{2}.str()], 1); + EXPECT_TRUE(json.contains("0x0000000000000001")); + EXPECT_TRUE(json.contains("0x0000000000000002")); + EXPECT_EQ(json["0x0000000000000001"], 0); + EXPECT_EQ(json["0x0000000000000002"], 1); ctx.mJobManager.CleanupJobs(); // "opdataset get active" command @@ -677,12 +677,12 @@ TEST_F(JobManagerTestSuite, BuildFinalResultString) ctx.mJobManager.RunJobs(); value = ctx.mJobManager.CollectJobsValue(); json = nlohmann::json::parse(value.ToString()); - EXPECT_TRUE(json.contains(XpanId{1}.str())); - EXPECT_TRUE(json.contains(XpanId{2}.str())); - EXPECT_TRUE(json[XpanId{1}.str()].contains("PanId")); - EXPECT_TRUE(json[XpanId{2}.str()].contains("PanId")); - EXPECT_STREQ("0x0001", json[XpanId{1}.str()]["PanId"].get().c_str()); - EXPECT_STREQ("0x0002", json[XpanId{2}.str()]["PanId"].get().c_str()); + EXPECT_TRUE(json.contains("0x0000000000000001")); + EXPECT_TRUE(json.contains("0x0000000000000002")); + EXPECT_TRUE(json["0x0000000000000001"].contains("PanId")); + EXPECT_TRUE(json["0x0000000000000002"].contains("PanId")); + EXPECT_STREQ("0x0001", json["0x0000000000000001"]["PanId"].get().c_str()); + EXPECT_STREQ("0x0002", json["0x0000000000000002"]["PanId"].get().c_str()); ctx.mJobManager.CleanupJobs(); // "opdataset set securitypolicy" command @@ -696,10 +696,10 @@ TEST_F(JobManagerTestSuite, BuildFinalResultString) ctx.mJobManager.RunJobs(); value = ctx.mJobManager.CollectJobsValue(); json = nlohmann::json::parse(value.ToString()); - EXPECT_TRUE(json.contains(XpanId{1}.str())); - EXPECT_TRUE(json.contains(XpanId{2}.str())); - EXPECT_TRUE(json[XpanId{1}.str()]); - EXPECT_TRUE(json[XpanId{2}.str()]); + EXPECT_TRUE(json.contains("0x0000000000000001")); + EXPECT_TRUE(json.contains("0x0000000000000002")); + EXPECT_TRUE(json["0x0000000000000001"]); + EXPECT_TRUE(json["0x0000000000000002"]); ctx.mJobManager.CleanupJobs(); // "stop" command @@ -709,9 +709,9 @@ TEST_F(JobManagerTestSuite, BuildFinalResultString) ctx.mJobManager.RunJobs(); value = ctx.mJobManager.CollectJobsValue(); json = nlohmann::json::parse(value.ToString()); - EXPECT_TRUE(json.contains(XpanId{1}.str())); - EXPECT_TRUE(json.contains(XpanId{2}.str())); - EXPECT_TRUE(json[XpanId{1}.str()]); - EXPECT_TRUE(json[XpanId{2}.str()]); + EXPECT_TRUE(json.contains("0x0000000000000001")); + EXPECT_TRUE(json.contains("0x0000000000000002")); + EXPECT_TRUE(json["0x0000000000000001"]); + EXPECT_TRUE(json["0x0000000000000002"]); ctx.mJobManager.CleanupJobs(); } diff --git a/src/app/commissioner_app.cpp b/src/app/commissioner_app.cpp index 6eb7cb2b..fbd612e3 100644 --- a/src/app/commissioner_app.cpp +++ b/src/app/commissioner_app.cpp @@ -523,7 +523,7 @@ Error CommissionerApp::GetExtendedPanId(ByteArray &aExtendedPanId) const VerifyOrExit(mActiveDataset.mPresentFlags & ActiveOperationalDataset::kExtendedPanIdBit, error = ERROR_NOT_FOUND("cannot find valid Extended PAN ID in Active Operational Dataset")); - aExtendedPanId = utils::Encode(mActiveDataset.mExtendedPanId.mValue); + aExtendedPanId = mActiveDataset.mExtendedPanId; exit: return error; @@ -536,7 +536,7 @@ Error CommissionerApp::SetExtendedPanId(const ByteArray &aExtendedPanId) VerifyOrExit(IsActive(), error = ERROR_INVALID_STATE("the commissioner is not active")); - activeDataset.mExtendedPanId = XpanId{utils::Decode(aExtendedPanId)}; + activeDataset.mExtendedPanId = aExtendedPanId; activeDataset.mPresentFlags |= ActiveOperationalDataset::kExtendedPanIdBit; SuccessOrExit(error = mCommissioner->SetActiveDataset(activeDataset)); @@ -680,7 +680,7 @@ Error CommissionerApp::SetNetworkName(const std::string &aNetworkName) return error; } -Error CommissionerApp::GetPanId(PanId &aPanId) +Error CommissionerApp::GetPanId(uint16_t &aPanId) { Error error; @@ -696,7 +696,7 @@ Error CommissionerApp::GetPanId(PanId &aPanId) return error; } -Error CommissionerApp::SetPanId(PanId aPanId, MilliSeconds aDelay) +Error CommissionerApp::SetPanId(uint16_t aPanId, MilliSeconds aDelay) { Error error; PendingOperationalDataset pendingDataset; diff --git a/src/app/commissioner_app.hpp b/src/app/commissioner_app.hpp index 288a0933..fe08d5df 100644 --- a/src/app/commissioner_app.hpp +++ b/src/app/commissioner_app.hpp @@ -202,8 +202,8 @@ class CommissionerApp : public CommissionerHandler MOCKABLE Error SetNetworkMasterKey(const ByteArray &aMasterKey, MilliSeconds aDelay); MOCKABLE Error GetNetworkName(std::string &aNetworkName) const; MOCKABLE Error SetNetworkName(const std::string &aNetworkName); - MOCKABLE Error GetPanId(PanId &aPanId); - MOCKABLE Error SetPanId(PanId aPanId, MilliSeconds aDelay); + MOCKABLE Error GetPanId(uint16_t &aPanId); + MOCKABLE Error SetPanId(uint16_t aPanId, MilliSeconds aDelay); MOCKABLE Error GetPSKc(ByteArray &aPSKc) const; MOCKABLE Error SetPSKc(const ByteArray &aPSKc); diff --git a/src/app/commissioner_app_dummy.cpp b/src/app/commissioner_app_dummy.cpp index f9024be2..248ab00a 100644 --- a/src/app/commissioner_app_dummy.cpp +++ b/src/app/commissioner_app_dummy.cpp @@ -303,13 +303,13 @@ Error CommissionerApp::SetNetworkName(const std::string &aNetworkName) return Error{}; } -Error CommissionerApp::GetPanId(PanId &aPanId) +Error CommissionerApp::GetPanId(uint16_t &aPanId) { UNUSED(aPanId); return Error{}; } -Error CommissionerApp::SetPanId(PanId aPanId, MilliSeconds aDelay) +Error CommissionerApp::SetPanId(uint16_t aPanId, MilliSeconds aDelay) { UNUSED(aPanId); UNUSED(aDelay); diff --git a/src/app/commissioner_app_mock.hpp b/src/app/commissioner_app_mock.hpp index 5ce32476..5b31862f 100644 --- a/src/app/commissioner_app_mock.hpp +++ b/src/app/commissioner_app_mock.hpp @@ -104,8 +104,8 @@ class CommissionerAppMock : public ::ot::commissioner::CommissionerApp MOCK_METHOD(Error, SetNetworkMasterKey, (const ByteArray &, MilliSeconds)); MOCK_METHOD(Error, GetNetworkName, (std::string &), (const)); MOCK_METHOD(Error, SetNetworkName, (const std::string &)); - MOCK_METHOD(Error, GetPanId, (PanId &)); - MOCK_METHOD(Error, SetPanId, (PanId, MilliSeconds)); + MOCK_METHOD(Error, GetPanId, (uint16_t &)); + MOCK_METHOD(Error, SetPanId, (uint16_t, MilliSeconds)); MOCK_METHOD(Error, GetPSKc, (ByteArray &), (const)); MOCK_METHOD(Error, SetPSKc, (const ByteArray &)); MOCK_METHOD(Error, GetSecurityPolicy, (SecurityPolicy &), (const)); diff --git a/src/app/json.cpp b/src/app/json.cpp index d8132358..7f24f91d 100644 --- a/src/app/json.cpp +++ b/src/app/json.cpp @@ -417,18 +417,6 @@ static void from_json(const Json &aJson, SecurityPolicy &aSecurityPolicy) #undef SET } -static void to_json(Json &aJson, const ot::commissioner::PanId &aPanId) -{ - aJson = std::string(aPanId); -} - -static void from_json(const Json &aJson, ot::commissioner::PanId &aPanId) -{ - std::string panIdStr; - panIdStr = aJson.get(); - SuccessOrThrow(aPanId.FromHex(panIdStr)); -} - static void to_json(Json &aJson, const ActiveOperationalDataset &aDataset) { #define SET_IF_PRESENT(name) \ @@ -438,9 +426,19 @@ static void to_json(Json &aJson, const ActiveOperationalDataset &aDataset) }; SET_IF_PRESENT(ActiveTimestamp); + SET_IF_PRESENT(NetworkName); SET_IF_PRESENT(Channel); SET_IF_PRESENT(ChannelMask); - SET_IF_PRESENT(ExtendedPanId); + + if (aDataset.mPresentFlags & ActiveOperationalDataset::kExtendedPanIdBit) + { + aJson["ExtendedPanId"] = utils::Hex(aDataset.mExtendedPanId); + } + + if (aDataset.mPresentFlags & ActiveOperationalDataset::kPanIdBit) + { + aJson["PanId"] = utils::Hex(aDataset.mPanId); + } if (aDataset.mPresentFlags & ActiveOperationalDataset::kMeshLocalPrefixBit) { @@ -448,20 +446,12 @@ static void to_json(Json &aJson, const ActiveOperationalDataset &aDataset) }; SET_IF_PRESENT(NetworkMasterKey); - SET_IF_PRESENT(NetworkName); - SET_IF_PRESENT(PanId); SET_IF_PRESENT(PSKc); SET_IF_PRESENT(SecurityPolicy); #undef SET_IF_PRESENT } -static void from_json(const Json &aJson, XpanId &aXpanId) -{ - std::string xpanStr = aJson.get(); - SuccessOrThrow(aXpanId.FromHex(xpanStr)); -} - static void from_json(const Json &aJson, ActiveOperationalDataset &aDataset) { #define SET_IF_PRESENT(name) \ @@ -472,9 +462,21 @@ static void from_json(const Json &aJson, ActiveOperationalDataset &aDataset) }; SET_IF_PRESENT(ActiveTimestamp); + SET_IF_PRESENT(NetworkName); SET_IF_PRESENT(Channel); SET_IF_PRESENT(ChannelMask); - SET_IF_PRESENT(ExtendedPanId); + + if (aJson.contains("ExtendedPanId")) + { + SuccessOrThrow(utils::Hex(aDataset.mExtendedPanId, aJson["ExtendedPanId"])); + aDataset.mPresentFlags |= ActiveOperationalDataset::kExtendedPanIdBit; + } + + if (aJson.contains("PanId")) + { + SuccessOrThrow(utils::ParseInteger(aDataset.mPanId, aJson["PanId"])); + aDataset.mPresentFlags |= ActiveOperationalDataset::kPanIdBit; + } if (aJson.contains("MeshLocalPrefix")) { @@ -485,8 +487,6 @@ static void from_json(const Json &aJson, ActiveOperationalDataset &aDataset) }; SET_IF_PRESENT(NetworkMasterKey); - SET_IF_PRESENT(NetworkName); - SET_IF_PRESENT(PanId); SET_IF_PRESENT(PSKc); SET_IF_PRESENT(SecurityPolicy); @@ -796,11 +796,6 @@ static void from_json(const nlohmann::json &aJson, BorderAgent::State &aState) void BorderAgentFromJson(BorderAgent &aAgent, const nlohmann::json &aJson) { BorderAgent agent; - auto json2xpan = [](const nlohmann::json &field) { - XpanId xpan; - Error error = xpan.FromHex(field.get()); - return error == ERROR_NONE ? xpan.mValue : XpanId::kEmptyXpanId; - }; #define SET_IF_PRESENT(field) \ do \ @@ -812,22 +807,18 @@ void BorderAgentFromJson(BorderAgent &aAgent, const nlohmann::json &aJson) } \ } while (false) -#define SET_IF_PRESENT_X(field) \ - do \ - { \ - if (aJson.contains(#field)) \ - { \ - agent.mPresentFlags |= BorderAgent::k##field##Bit; \ - agent.m##field = json2xpan(aJson.at(#field)); \ - } \ - } while (false) - SET_IF_PRESENT(Addr); SET_IF_PRESENT(Port); SET_IF_PRESENT(ThreadVersion); SET_IF_PRESENT(State); SET_IF_PRESENT(NetworkName); - SET_IF_PRESENT_X(ExtendedPanId); + + if (aJson.contains("ExtendedPanId")) + { + SuccessOrThrow(utils::ParseInteger(agent.mExtendedPanId, aJson["ExtendedPanId"])); + agent.mPresentFlags |= BorderAgent::kExtendedPanIdBit; + } + SET_IF_PRESENT(VendorName); SET_IF_PRESENT(ModelName); SET_IF_PRESENT(ActiveTimestamp); @@ -840,7 +831,6 @@ void BorderAgentFromJson(BorderAgent &aAgent, const nlohmann::json &aJson) SET_IF_PRESENT(ServiceName); #undef SET_IF_PRESENT -#undef SET_IF_PRESENT_X aAgent = agent; } @@ -863,21 +853,17 @@ void BorderAgentToJson(const BorderAgent &aAgent, nlohmann::json &aJson) } \ } while (false) -#define SET_IF_PRESENT_X(field) \ - do \ - { \ - if (aAgent.mPresentFlags & BorderAgent::k##field##Bit) \ - { \ - aJson[#field] = XpanId(aAgent.m##field).str(); \ - } \ - } while (false) - SET_IF_PRESENT(Addr); SET_IF_PRESENT(Port); SET_IF_PRESENT(ThreadVersion); SET_IF_PRESENT(State); SET_IF_PRESENT(NetworkName); - SET_IF_PRESENT_X(ExtendedPanId); + + if (aAgent.mPresentFlags & BorderAgent::kExtendedPanIdBit) + { + aJson["ExtendedPanId"] = utils::Hex(aAgent.mExtendedPanId); + } + SET_IF_PRESENT(VendorName); SET_IF_PRESENT(ModelName); SET_IF_PRESENT(ActiveTimestamp); @@ -890,7 +876,6 @@ void BorderAgentToJson(const BorderAgent &aAgent, nlohmann::json &aJson) SET_IF_PRESENT(ServiceName); #undef SET_IF_PRESENT -#undef SET_IF_PRESENT_X } } // namespace commissioner diff --git a/src/app/ps/CMakeLists.txt b/src/app/ps/CMakeLists.txt index 2db452a9..f999f9da 100644 --- a/src/app/ps/CMakeLists.txt +++ b/src/app/ps/CMakeLists.txt @@ -74,4 +74,10 @@ if (OT_COMM_TEST) ${PROJECT_SOURCE_DIR}/third_party/googletest/repo/googletest/include $ ) + + target_link_libraries(commissioner-ps-test + PUBLIC + commissioner-common + commissioner-app + ) endif (OT_COMM_TEST) diff --git a/src/app/ps/persistent_storage_json.cpp b/src/app/ps/persistent_storage_json.cpp index 5f153961..006a6a55 100644 --- a/src/app/ps/persistent_storage_json.cpp +++ b/src/app/ps/persistent_storage_json.cpp @@ -285,9 +285,9 @@ PersistentStorage::Status PersistentStorageJson::Get(BorderRouterId const &aId, aRetValue.mAgent.mNetworkName = nwk.mName; aRetValue.mAgent.mPresentFlags |= BorderAgent::kNetworkNameBit; } - if (nwk.mXpan.mValue != XpanId::kEmptyXpanId) + if (nwk.mXpan != 0) { - aRetValue.mAgent.mExtendedPanId = nwk.mXpan.mValue; + aRetValue.mAgent.mExtendedPanId = nwk.mXpan; aRetValue.mAgent.mPresentFlags |= BorderAgent::kExtendedPanIdBit; } if (nwk.mDomainId.mId != EMPTY_ID) @@ -371,8 +371,7 @@ PersistentStorage::Status PersistentStorageJson::Lookup(Network const &aValue, s (aValue.mId.mId == EMPTY_ID || (el.mId.mId == aValue.mId.mId)) && (aValue.mDomainId.mId == EMPTY_ID || (el.mDomainId.mId == aValue.mDomainId.mId)) && (aValue.mName.empty() || (aValue.mName == el.mName)) && - (aValue.mXpan.mValue == XpanId::kEmptyXpanId || aValue.mXpan == el.mXpan) && - (aValue.mPan.mValue == PanId::kEmptyPanId || (aValue.mPan.mValue == el.mPan.mValue)) && + (aValue.mXpan == 0 || aValue.mXpan == el.mXpan) && (aValue.mPan == 0 || (aValue.mPan == el.mPan)) && (aValue.mMlp.empty() || CaseInsensitiveEqual(aValue.mMlp, el.mMlp)) && (aValue.mChannel == 0 || (aValue.mChannel == el.mChannel)); @@ -476,8 +475,7 @@ PersistentStorage::Status PersistentStorageJson::LookupAny(Network const &aValue (aValue.mId.mId == EMPTY_ID || (el.mId.mId == aValue.mId.mId)) || (aValue.mDomainId.mId == EMPTY_ID || (el.mDomainId.mId == aValue.mDomainId.mId)) || (aValue.mName.empty() || (aValue.mName == el.mName)) || - (aValue.mXpan.mValue == XpanId::kEmptyXpanId || aValue.mXpan == el.mXpan) || - (aValue.mPan.mValue == PanId::kEmptyPanId || (aValue.mPan.mValue == el.mPan.mValue)) || + (aValue.mXpan == 0 || aValue.mXpan == el.mXpan) || (aValue.mPan == 0 || (aValue.mPan == el.mPan)) || (aValue.mMlp.empty() || CaseInsensitiveEqual(aValue.mMlp, el.mMlp)) || (aValue.mChannel == 0 || (aValue.mChannel == el.mChannel)); diff --git a/src/app/ps/persistent_storage_json_test.cpp b/src/app/ps/persistent_storage_json_test.cpp index b51ee828..295dc3f2 100644 --- a/src/app/ps/persistent_storage_json_test.cpp +++ b/src/app/ps/persistent_storage_json_test.cpp @@ -128,17 +128,14 @@ TEST(PersistentStorageJsonTestSuite, AddNetwork) NetworkId newId; - EXPECT_TRUE( - psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk1", XpanId{0xFFFFFFFFFFFFFFF1ll}, 11, 0xFFF1, "2000:aaa1::0/8", 1}, - newId) == PersistentStorage::Status::kSuccess); + EXPECT_TRUE(psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk1", 0xFFFFFFFFFFFFFFF1ll, 11, 0xFFF1, "2000:aaa1::0/8", 1}, + newId) == PersistentStorage::Status::kSuccess); EXPECT_TRUE(newId.mId == 0); - EXPECT_TRUE( - psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk2", XpanId{0xFFFFFFFFFFFFFFF2ll}, 11, 0xFFF2, "2000:aaa2::0/8", 1}, - newId) == PersistentStorage::Status::kSuccess); + EXPECT_TRUE(psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk2", 0xFFFFFFFFFFFFFFF2ll, 11, 0xFFF2, "2000:aaa2::0/8", 1}, + newId) == PersistentStorage::Status::kSuccess); EXPECT_TRUE(newId.mId == 1); - EXPECT_TRUE( - psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk3", XpanId{0xFFFFFFFFFFFFFFF3ll}, 11, 0xFFF3, "2000:aaa3::0/8", 1}, - newId) == PersistentStorage::Status::kSuccess); + EXPECT_TRUE(psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk3", 0xFFFFFFFFFFFFFFF3ll, 11, 0xFFF3, "2000:aaa3::0/8", 1}, + newId) == PersistentStorage::Status::kSuccess); EXPECT_TRUE(newId.mId == 2); EXPECT_TRUE(psj.Close() == PersistentStorage::Status::kSuccess); @@ -212,9 +209,8 @@ TEST(PersistentStorageJsonTestSuite, DelNetwork) EXPECT_TRUE(psj.Open() == PersistentStorage::Status::kSuccess); NetworkId newId; - EXPECT_TRUE( - psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk1", XpanId{0xFFFFFFFFFFFFFFF1ll}, 11, 0xFFF1, "2000:aaa1::0/8", 1}, - newId) == PersistentStorage::Status::kSuccess); + EXPECT_TRUE(psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk1", 0xFFFFFFFFFFFFFFF1ll, 11, 0xFFF1, "2000:aaa1::0/8", 1}, + newId) == PersistentStorage::Status::kSuccess); EXPECT_TRUE(newId.mId == 0); EXPECT_TRUE(psj.Del(NetworkId(0)) == PersistentStorage::Status::kSuccess); @@ -658,17 +654,14 @@ TEST(PersistentStorageJsonTestSuite, LookupNetwork) // Populate storage with initial data NetworkId newId; - EXPECT_TRUE( - psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk1", XpanId{0xFFFFFFFFFFFFFFF1ll}, 11, 0xFFF1, "2000:aaa1::0/8", 1}, - newId) == PersistentStorage::Status::kSuccess); + EXPECT_TRUE(psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk1", 0xFFFFFFFFFFFFFFF1ll, 11, 0xFFF1, "2000:aaa1::0/8", 1}, + newId) == PersistentStorage::Status::kSuccess); EXPECT_TRUE(newId.mId == 0); - EXPECT_TRUE( - psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk2", XpanId{0xFFFFFFFFFFFFFFF2ll}, 11, 0xFFF2, "2000:aaa2::0/8", 1}, - newId) == PersistentStorage::Status::kSuccess); + EXPECT_TRUE(psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk2", 0xFFFFFFFFFFFFFFF2ll, 11, 0xFFF2, "2000:aaa2::0/8", 1}, + newId) == PersistentStorage::Status::kSuccess); EXPECT_TRUE(newId.mId == 1); - EXPECT_TRUE( - psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk3", XpanId{0xFFFFFFFFFFFFFFF3ll}, 11, 0xFFF3, "2000:aaa3::0/8", 1}, - newId) == PersistentStorage::Status::kSuccess); + EXPECT_TRUE(psj.Add(Network{EMPTY_ID, EMPTY_ID, "nwk3", 0xFFFFFFFFFFFFFFF3ll, 11, 0xFFF3, "2000:aaa3::0/8", 1}, + newId) == PersistentStorage::Status::kSuccess); EXPECT_TRUE(newId.mId == 2); // The test diff --git a/src/app/ps/registry.cpp b/src/app/ps/registry.cpp index eef177af..15956b8b 100644 --- a/src/app/ps/registry.cpp +++ b/src/app/ps/registry.cpp @@ -175,7 +175,7 @@ Registry::Status Registry::Add(BorderAgent const &aValue) // Decided: update network aName in the network entity if ((aValue.mPresentFlags & BorderAgent::kExtendedPanIdBit) != 0) { - nwk.mXpan = XpanId{aValue.mExtendedPanId}; + nwk.mXpan = aValue.mExtendedPanId; } else { @@ -199,7 +199,7 @@ Registry::Status Registry::Add(BorderAgent const &aValue) nwk.mName = aValue.mNetworkName; } nwk.mDomainId = dom.mId; - nwk.mXpan = XpanId{aValue.mExtendedPanId}; + nwk.mXpan = aValue.mExtendedPanId; // Provisionally set network's CCM flag considering // advertised Connection Mode. @@ -293,7 +293,7 @@ Registry::Status Registry::GetBorderRouter(const BorderRouterId aRawId, BorderRo return MapStatus(mStorage->Get(aRawId, br)); } -Registry::Status Registry::GetBorderRoutersInNetwork(const XpanId aXpan, BorderRouterArray &aRet) +Registry::Status Registry::GetBorderRoutersInNetwork(uint64_t aXpan, BorderRouterArray &aRet) { Network nwk; BorderRouter pred; @@ -306,7 +306,7 @@ Registry::Status Registry::GetBorderRoutersInNetwork(const XpanId aXpan, BorderR return status; } -Registry::Status Registry::GetNetworkXpansInDomain(const std::string &aDomainName, XpanIdArray &aRet) +Registry::Status Registry::GetNetworkXpansInDomain(const std::string &aDomainName, std::vector &aRet) { NetworkArray networks; Registry::Status status = GetNetworksInDomain(aDomainName, networks); @@ -421,9 +421,9 @@ Registry::Status Registry::GetAllNetworks(NetworkArray &aRet) return status; } -Registry::Status Registry::GetNetworkXpansByAliases(const StringArray &aAliases, - XpanIdArray &aRet, - StringArray &aUnresolved) +Registry::Status Registry::GetNetworkXpansByAliases(const StringArray &aAliases, + std::vector &aRet, + StringArray &aUnresolved) { NetworkArray networks; Registry::Status status = GetNetworksByAliases(aAliases, networks, aUnresolved); @@ -484,23 +484,32 @@ Registry::Status Registry::GetNetworksByAliases(const StringArray &aAliases, } else { - Network nwk; - XpanId xpid; - PanId pid; + Network nwk; + uint64_t xpid; + uint16_t pid; status = Registry::Status::kNotFound; - if (xpid.FromHex(alias) == ERROR_NONE) + if (utils::ParseInteger(xpid, alias) == ERROR_NONE) { status = GetNetworkByXpan(xpid, nwk); } + if (status != Registry::Status::kSuccess) { status = GetNetworkByName(alias, nwk); } - if (status != Registry::Status::kSuccess && pid.FromHex(alias) == ERROR_NONE) + + if (status != Registry::Status::kSuccess) { - status = GetNetworkByPan(alias, nwk); + bool hasHexPrefix = utils::ToLower(alias.substr(0, 2)) != "0x"; + std::string aliasAsPanId = std::string(hasHexPrefix ? "0x" : "") + alias; + + if (utils::ParseInteger(pid, aliasAsPanId) == ERROR_NONE) + { + status = GetNetworkByPan(aliasAsPanId, nwk); + } } + if (status == Registry::Status::kSuccess) { networks.push_back(nwk); @@ -533,7 +542,7 @@ Registry::Status Registry::ForgetCurrentNetwork() return SetCurrentNetwork(NetworkId{}); } -Registry::Status Registry::SetCurrentNetwork(const XpanId &aXpan) +Registry::Status Registry::SetCurrentNetwork(uint64_t aXpan) { Network nwk; Registry::Status status; @@ -571,7 +580,7 @@ Registry::Status Registry::GetCurrentNetwork(Network &aRet) : MapStatus(mStorage->Get(networkId, aRet)); } -Registry::Status Registry::GetCurrentNetworkXpan(XpanId &aRet) +Registry::Status Registry::GetCurrentNetworkXpan(uint64_t &aRet) { Registry::Status status; Network nwk; @@ -592,7 +601,7 @@ Registry::Status Registry::LookupOne(const Network &aPred, Network &aRet) return status; } -Registry::Status Registry::GetNetworkByXpan(const XpanId &aXpan, Network &aRet) +Registry::Status Registry::GetNetworkByXpan(uint64_t aXpan, Network &aRet) { Network nwk{}; nwk.mXpan = aXpan; @@ -608,9 +617,10 @@ Registry::Status Registry::GetNetworkByName(const std::string &aName, Network &a Registry::Status Registry::GetNetworkByPan(const std::string &aPan, Network &aRet) { - Network nwk{}; - PanId panId; - if (panId.FromHex(aPan).GetCode() != ErrorCode::kNone) + Network nwk{}; + uint16_t panId = 0; + + if (utils::ParseInteger(panId, aPan).GetCode() != ErrorCode::kNone) { return Registry::Status::kError; } @@ -618,7 +628,7 @@ Registry::Status Registry::GetNetworkByPan(const std::string &aPan, Network &aRe return LookupOne(nwk, aRet); } -Registry::Status Registry::GetDomainNameByXpan(const XpanId &aXpan, std::string &aName) +Registry::Status Registry::GetDomainNameByXpan(uint64_t aXpan, std::string &aName) { Registry::Status status; Network nwk; @@ -753,13 +763,13 @@ Registry::Status Registry::DropDomainIfEmpty(const DomainId &aDomainId) Registry::Status Registry::DeleteBorderRoutersInDomain(const std::string &aDomainName) { - Domain dom; - DomainArray doms; - Registry::Status status; - Network current; - XpanIdArray xpans; - StringArray aAliases; - StringArray aUnresolved; + Domain dom; + DomainArray doms; + Registry::Status status; + Network current; + std::vector xpans; + StringArray aAliases; + StringArray aUnresolved; dom.mName = aDomainName; VerifyOrExit((status = MapStatus(mStorage->Lookup(dom, doms))) == Registry::Status::kSuccess); @@ -779,7 +789,7 @@ Registry::Status Registry::DeleteBorderRoutersInDomain(const std::string &aDomai for (auto &&xpan : xpans) { - aAliases.push_back(XpanId(xpan).str()); + aAliases.push_back(utils::Hex(xpan)); } VerifyOrExit((status = DeleteBorderRoutersInNetworks(aAliases, aUnresolved)) == Registry::Status::kSuccess); VerifyOrExit(aUnresolved.empty(), status = Registry::Status::kAmbiguity); diff --git a/src/app/ps/registry.hpp b/src/app/ps/registry.hpp index af89604a..97cc57df 100644 --- a/src/app/ps/registry.hpp +++ b/src/app/ps/registry.hpp @@ -136,7 +136,7 @@ class Registry * @param[in] aXpan network's XPAN ID * @param[out] aRetValue resultant array of @ref BorderRouter records */ - Status GetBorderRoutersInNetwork(XpanId aXpan, BorderRouterArray &aRetValue); + Status GetBorderRoutersInNetwork(uint64_t aXpan, BorderRouterArray &aRetValue); /** * Get networks of the domain @@ -154,7 +154,7 @@ class Registry * @param[out] aRetValue vector of network XPAN IDs belonging to the domain * @note Network XPAN IDs will be appended to the end of the output vector */ - Status GetNetworkXpansInDomain(const std::string &aDomainName, XpanIdArray &aRetValue); + Status GetNetworkXpansInDomain(const std::string &aDomainName, std::vector &aRetValue); /** * Get list of all domains @@ -191,12 +191,14 @@ class Registry * @param[out] aRetValue list of network XPAN IDs * @param[out] aUnresolved list of aliases failed to resolve */ - Status GetNetworkXpansByAliases(const StringArray &aAliases, XpanIdArray &aRetValue, StringArray &aUnresolved); + Status GetNetworkXpansByAliases(const StringArray &aAliases, + std::vector &aRetValue, + StringArray &aUnresolved); /** * Set current network. */ - Status SetCurrentNetwork(const XpanId &aXpan); + Status SetCurrentNetwork(uint64_t aXpan); /** * Set current network by border router specified. @@ -219,7 +221,7 @@ class Registry * * @param [out] aRetValue current network XPAN ID */ - Status GetCurrentNetworkXpan(XpanId &aRetValue); + Status GetCurrentNetworkXpan(uint64_t &aRetValue); /** * Get network with specified extended PAN id @@ -232,7 +234,7 @@ class Registry * @li @ref REG_DATA_INVALID is more than one network was found * @li @ref REG_ERROR on other errors */ - Status GetNetworkByXpan(const XpanId &aXpan, Network &aRetValue); + Status GetNetworkByXpan(uint64_t aXpan, Network &aRetValue); /** * Get network with specified name @@ -271,7 +273,7 @@ class Registry * @li @ref REG_AMBUGUITY is more than one network was found * @li @ref REG_ERROR on other errors */ - Status GetDomainNameByXpan(const XpanId &aXpan, std::string &aName); + Status GetDomainNameByXpan(uint64_t aXpan, std::string &aName); /** * Remove border router record. diff --git a/src/app/ps/registry_entries.cpp b/src/app/ps/registry_entries.cpp index 2ee21494..e9586800 100644 --- a/src/app/ps/registry_entries.cpp +++ b/src/app/ps/registry_entries.cpp @@ -156,8 +156,8 @@ void to_json(json &aJson, const Network &aValue) aJson = json{{JSON_ID, aValue.mId}, {JSON_DOM_REF, aValue.mDomainId}, {JSON_NAME, aValue.mName}, - {JSON_PAN, std::string(aValue.mPan)}, - {JSON_XPAN, std::string(aValue.mXpan)}, + {JSON_PAN, utils::Hex(aValue.mPan)}, + {JSON_XPAN, utils::Hex(aValue.mXpan)}, {JSON_CHANNEL, aValue.mChannel}, {JSON_MLP, aValue.mMlp}, {JSON_CCM, aValue.mCcm}}; @@ -165,15 +165,16 @@ void to_json(json &aJson, const Network &aValue) void from_json(const json &aJson, Network &aValue) { + std::string hexStr; + aJson.at(JSON_ID).get_to(aValue.mId); aJson.at(JSON_DOM_REF).get_to(aValue.mDomainId); aJson.at(JSON_NAME).get_to(aValue.mName); - std::string hexStr; aJson.at(JSON_PAN).get_to(hexStr); - SuccessOrThrow(aValue.mPan.FromHex(hexStr)); + SuccessOrThrow(utils::ParseInteger(aValue.mPan, hexStr)); aJson.at(JSON_XPAN).get_to(hexStr); - SuccessOrThrow(aValue.mXpan.FromHex(hexStr)); + SuccessOrThrow(utils::ParseInteger(aValue.mXpan, hexStr)); aJson.at(JSON_CHANNEL).get_to(aValue.mChannel); aJson.at(JSON_MLP).get_to(aValue.mMlp); @@ -407,14 +408,14 @@ Domain::Domain() { } -Network::Network(NetworkId const &aId, - DomainId const &aDomainId, - std::string const &aName, - XpanId const &aXpan, - unsigned int const aChannel, - uint16_t const aPan, - std::string const &aMlp, - int const aCcm) +Network::Network(const NetworkId &aId, + const DomainId &aDomainId, + const std::string &aName, + uint64_t aXpan, + unsigned int aChannel, + uint16_t aPan, + const std::string &aMlp, + int aCcm) : mId(aId) , mDomainId(aDomainId) , mName(aName) @@ -427,7 +428,7 @@ Network::Network(NetworkId const &aId, } Network::Network() - : Network(EMPTY_ID, EMPTY_ID, "", XpanId{}, 0, 0, "", -1) + : Network(EMPTY_ID, EMPTY_ID, "", 0, 0, 0, "", -1) { } diff --git a/src/app/ps/registry_entries.hpp b/src/app/ps/registry_entries.hpp index cf69e8c4..39dac0cf 100644 --- a/src/app/ps/registry_entries.hpp +++ b/src/app/ps/registry_entries.hpp @@ -138,20 +138,20 @@ struct Network NetworkId mId; /**< unique mId in registry */ DomainId mDomainId; /**< reference to the domain the network belongs to */ std::string mName; /**< network name */ - XpanId mXpan; /**< Extended PAN_ID */ + uint64_t mXpan; /**< Extended PAN_ID */ unsigned int mChannel; /**< network channel */ - PanId mPan; /**< PAN_ID */ + uint16_t mPan; /**< PAN_ID */ std::string mMlp; /**< Mesh-local prefix */ int mCcm; /**< Commercial commissioning mode;<0 not set, * 0 false, >0 true */ - Network(NetworkId const &aId, - DomainId const &aDomainId, - std::string const &aName, - XpanId const &aXpan, + Network(const NetworkId &aId, + const DomainId &aDomainId, + const std::string &aName, + uint64_t aXpan, unsigned int aChannel, uint16_t aPan, - std::string const &aMlp, + const std::string &aMlp, int aCcm); Network(); }; diff --git a/src/app/ps/registry_test.cpp b/src/app/ps/registry_test.cpp index 4b8a2bc7..867b2838 100644 --- a/src/app/ps/registry_test.cpp +++ b/src/app/ps/registry_test.cpp @@ -31,15 +31,19 @@ * The file implements registry test suite. */ -#include #include +#include + +#include #include "app/cli/console.hpp" #include "app/ps/registry.hpp" +#include "common/utils.hpp" #define INFO(str) Console::Write(str) using namespace ot::commissioner::persistent_storage; +using namespace ot::commissioner::utils; using namespace ot::commissioner; const char json_path[] = "./tmp/registry_test.json"; @@ -87,7 +91,7 @@ TEST(RegJson, CreateBorderRouterFromBorderAgent) EXPECT_TRUE(reg.GetBorderRouter(BorderRouterId{0}, ret_val) == Registry::Status::kSuccess); EXPECT_TRUE(ret_val.mNetworkId.mId == 0); Network nwk; - EXPECT_TRUE(reg.GetNetworkByXpan(XpanId{0}, nwk) == Registry::Status::kSuccess); + EXPECT_TRUE(reg.GetNetworkByXpan(0, nwk) == Registry::Status::kSuccess); EXPECT_TRUE(nwk.mDomainId.mId == EMPTY_ID); } @@ -159,7 +163,7 @@ TEST(RegJson, CreateBorderRouterFromBorderAgent) EXPECT_TRUE((val.mAgent.mPresentFlags & (BorderAgent::kAddrBit | BorderAgent::kPortBit)) == (BorderAgent::kAddrBit | BorderAgent::kPortBit)); EXPECT_TRUE(val.mAgent.mAddr == "1.1.1.1"); - INFO(val.mAgent.mNetworkName + " : " + XpanId(val.mAgent.mExtendedPanId).str()); + INFO(val.mAgent.mNetworkName + " : " + utils::Hex(val.mAgent.mExtendedPanId)); Network nwk; EXPECT_TRUE(reg.GetNetworkByXpan(val.mAgent.mExtendedPanId, nwk) == Registry::Status::kSuccess); // Modify explicitly diff --git a/src/common/error.cpp b/src/common/error.cpp index 37c0f6ac..7467cd9a 100644 --- a/src/common/error.cpp +++ b/src/common/error.cpp @@ -42,7 +42,7 @@ namespace ot { namespace commissioner { // Returns the std::string representation of the status code. -static std::string ErrorCodeToString(ErrorCode code) +std::string ErrorCodeToString(ErrorCode code) { switch (code) { diff --git a/src/common/utils.hpp b/src/common/utils.hpp index fa900ffa..c48286fa 100644 --- a/src/common/utils.hpp +++ b/src/common/utils.hpp @@ -42,6 +42,7 @@ #include "commissioner/defines.hpp" #include "commissioner/error.hpp" +#include "common/error_macros.hpp" #define ASSERT(aCondition) \ do \ @@ -188,6 +189,33 @@ std::string ToLower(const std::string &aStr); bool CaseInsensitiveEqual(const std::string &aLhs, const std::string &aRhs); +/** + * Returns the Hex string of an integer with zero paddings. + * + * For example, it returns "0xface" for integer 0xface. + */ +template std::string Hex(T aInteger) +{ + return std::string("0x") + Hex(Encode(aInteger)); +} + +template Error ParseInteger(T &aInteger, const std::string &aStr) +{ + Error error; + uint64_t integer; + char *endPtr = nullptr; + + integer = strtoull(aStr.c_str(), &endPtr, 0); + + VerifyOrExit(endPtr != nullptr && endPtr == aStr.c_str() + aStr.length(), + error = ERROR_INVALID_ARGS("{} is not a valid integer", aStr)); + + aInteger = integer; + +exit: + return error; +} + } // namespace utils } // namespace commissioner diff --git a/src/common/utils_test.cpp b/src/common/utils_test.cpp index 0d228e63..b454e59d 100644 --- a/src/common/utils_test.cpp +++ b/src/common/utils_test.cpp @@ -118,6 +118,29 @@ TEST(UtilsTest, HexEncodingDecoding_DecodingHexStringWithInvalidCharactersShould EXPECT_EQ(utils::Hex(buf, "00010g"), ErrorCode::kInvalidArgs); } +TEST(UtilsTest, ParseInteger_HexStringShouldSuccess) +{ + int value; + + EXPECT_EQ(utils::ParseInteger(value, "0xface"), ErrorCode::kNone); + EXPECT_EQ(value, 0xface); +} + +TEST(UtilsTest, ParseInteger_DecimalStringShouldSuccess) +{ + int value; + + EXPECT_EQ(utils::ParseInteger(value, "65535"), ErrorCode::kNone); + EXPECT_EQ(value, 65535); +} + +TEST(UtilsTest, ParseInteger_IntegerWithTrailingNonDigitsShouldFail) +{ + int value; + + EXPECT_EQ(utils::ParseInteger(value, "0xfacegg"), ErrorCode::kInvalidArgs); +} + } // namespace commissioner } // namespace ot diff --git a/src/java/commissioner.i b/src/java/commissioner.i index 4d65d5aa..65f381e3 100644 --- a/src/java/commissioner.i +++ b/src/java/commissioner.i @@ -169,18 +169,12 @@ namespace commissioner { uint32_t aTimeout); %ignore Commissioner::RequestToken(Handler aHandler, const std::string &aAddr, uint16_t aPort); - // Remove operators and move constructor of Error, XpanId, PanId. + // Remove operators and move constructor of Error. %ignore Error::operator=(const Error &aError); %ignore Error::Error(Error &&aError) noexcept; %ignore Error::operator=(Error &&aError) noexcept; %ignore Error::operator==(const Error &aOther) const; %ignore Error::operator!=(const Error &aOther) const; - %ignore XpanId::operator==(const XpanId &aOther) const; - %ignore XpanId::operator!=(const uint64_t aOther) const; - %ignore XpanId::operator<(const XpanId aOther) const; - %ignore XpanId::operator std::string() const; - %ignore PanId::operator=(uint16_t aValue); - %ignore PanId::operator uint16_t() const; %ignore operator==(const Error &aError, const ErrorCode &aErrorCode); %ignore operator!=(const Error &aError, const ErrorCode &aErrorCode); %ignore operator==(const ErrorCode &aErrorCode, const Error &aError); diff --git a/src/library/commissioner_impl.cpp b/src/library/commissioner_impl.cpp index de96b158..57370d5a 100644 --- a/src/library/commissioner_impl.cpp +++ b/src/library/commissioner_impl.cpp @@ -1488,7 +1488,7 @@ Error CommissionerImpl::DecodeActiveOperationalDataset(ActiveOperationalDataset if (auto extendedPanId = tlvSet[tlv::Type::kExtendedPanId]) { - dataset.mExtendedPanId = XpanId{utils::Decode(extendedPanId->GetValue())}; + dataset.mExtendedPanId = extendedPanId->GetValue(); dataset.mPresentFlags |= ActiveOperationalDataset::kExtendedPanIdBit; } @@ -1627,7 +1627,7 @@ Error CommissionerImpl::EncodeActiveOperationalDataset(coap::Request if (aDataset.mPresentFlags & ActiveOperationalDataset::kExtendedPanIdBit) { - SuccessOrExit(error = AppendTlv(aRequest, {tlv::Type::kExtendedPanId, aDataset.mExtendedPanId.mValue})); + SuccessOrExit(error = AppendTlv(aRequest, {tlv::Type::kExtendedPanId, aDataset.mExtendedPanId})); } if (aDataset.mPresentFlags & ActiveOperationalDataset::kMeshLocalPrefixBit) @@ -1647,7 +1647,7 @@ Error CommissionerImpl::EncodeActiveOperationalDataset(coap::Request if (aDataset.mPresentFlags & ActiveOperationalDataset::kPanIdBit) { - SuccessOrExit(error = AppendTlv(aRequest, {tlv::Type::kPanId, aDataset.mPanId.mValue})); + SuccessOrExit(error = AppendTlv(aRequest, {tlv::Type::kPanId, aDataset.mPanId})); } if (aDataset.mPresentFlags & ActiveOperationalDataset::kPSKcBit) diff --git a/src/library/network_data.cpp b/src/library/network_data.cpp index cbb8cc39..c062d2e4 100644 --- a/src/library/network_data.cpp +++ b/src/library/network_data.cpp @@ -123,123 +123,6 @@ std::string Ipv6PrefixToString(ByteArray aPrefix) return addr.ToString() + "/" + std::to_string(prefixLength); } -XpanId::XpanId(uint64_t val) - : mValue(val) -{ -} - -XpanId::XpanId() - : XpanId(kEmptyXpanId) -{ -} - -std::string XpanId::str() const -{ - return std::string(*this); -} - -bool XpanId::operator==(const XpanId &aOther) const -{ - return mValue == aOther.mValue; -} - -bool XpanId::operator!=(const XpanId &aOther) const -{ - return !(*this == aOther); -} - -bool XpanId::operator<(const XpanId &aOther) const -{ - return mValue < aOther.mValue; -} - -XpanId::operator std::string() const -{ - std::ostringstream value; - value << std::uppercase << std::hex << std::setw(sizeof(mValue) * 2) << std::setfill('0') << mValue; - return value.str(); -} - -/** - * Converts hex string to the corresponding integer type. - * @attention Makes no validity checks. - */ -Error XpanId::FromHex(const std::string &aInput) -{ - mValue = 0; - - std::string input = aInput; - if (utils::ToLower(input.substr(0, 2)) == "0x") - { - input = input.substr(2); - } - if (input.empty() || input.length() > 16) - return ERROR_BAD_FORMAT("{}: wrong XPAN ID string length", input.length()); - for (auto c : input) - { - if (!std::isxdigit(c)) - { - return ERROR_BAD_FORMAT("{}: not a hex string", input); - } - } - - std::istringstream is(input); - is >> std::hex >> mValue; - return ERROR_NONE; -} - -PanId::PanId(uint16_t aValue) - : mValue(aValue) -{ -} - -PanId::PanId() - : PanId(kEmptyPanId) -{ -} - -PanId &PanId::operator=(uint16_t aValue) -{ - mValue = aValue; - return *this; -} - -PanId::operator uint16_t() const -{ - return mValue; -} - -PanId::operator std::string() const -{ - std::ostringstream value; - value << "0x" << std::uppercase << std::hex << std::setw(sizeof(mValue) * 2) << std::setfill('0') << mValue; - return value.str(); -} - -Error PanId::FromHex(const std::string &aInput) -{ - mValue = 0; - - std::string input = aInput; - if (utils::ToLower(input.substr(0, 2)) == "0x") - { - input = input.substr(2); - } - if (input.empty() || input.length() > 4) - return ERROR_BAD_FORMAT("{}: wrong PAN ID string length", input.length()); - for (auto c : input) - { - if (!std::isxdigit(c)) - { - return ERROR_BAD_FORMAT("{}: not a hex string", input); - } - } - - std::istringstream is(input); - is >> std::hex >> mValue; - return ERROR_NONE; -} - ActiveOperationalDataset::ActiveOperationalDataset() : mActiveTimestamp(Timestamp::Cur()) , mPresentFlags(kActiveTimestampBit) diff --git a/tests/integration/test_domain_syntax.sh b/tests/integration/test_domain_syntax.sh index d41d3074..468edd64 100755 --- a/tests/integration/test_domain_syntax.sh +++ b/tests/integration/test_domain_syntax.sh @@ -75,7 +75,7 @@ test_select_identify() { send_command_to_commissioner "network select thread1" send_command_to_commissioner "network identify" "thread1" - send_command_to_commissioner "network select 2222222222222222" + send_command_to_commissioner "network select 0x2222222222222222" send_command_to_commissioner "network identify" "thread2" send_command_to_commissioner "network select none" @@ -151,10 +151,10 @@ test_start_stop_mn_all() { commissioner_mdns_scan_import ${CUR_DIR}/etc/br_scan_initial send_command_to_commissioner "start --nwk all" - send_command_to_commissioner "active --nwk all" 'DEAD00BEEF00CAFE.*true' - send_command_to_commissioner "sessionid --nwk all" 'DEAD00BEEF00CAFE": \d*' - send_command_to_commissioner "opdataset get active --nwk all" 'DEAD00BEEF00CAFE": {' - send_command_to_commissioner "commdataset get --nwk all" 'DEAD00BEEF00CAFE": {' + send_command_to_commissioner "active --nwk all" '0xdead00beef00cafe.*true' + send_command_to_commissioner "sessionid --nwk all" '0xdead00beef00cafe": \d*' + send_command_to_commissioner "opdataset get active --nwk all" '0xdead00beef00cafe": {' + send_command_to_commissioner "commdataset get --nwk all" '0xdead00beef00cafe": {' send_command_to_commissioner "opdataset set securitypolicy 1000 ff --nwk all" send_command_to_commissioner "opdataset get pending --nwk all" send_command_to_commissioner "stop --nwk all" @@ -179,12 +179,12 @@ test_start_stop_mn_other() { mdns_hosts_map_addresses commissioner_mdns_scan_import ${CUR_DIR}/etc/br_scan_initial - send_command_to_commissioner "network select 2222222222222222" + send_command_to_commissioner "network select 0x2222222222222222" send_command_to_commissioner "start --nwk other" send_command_to_commissioner "active --nwk other" '1111111111111111": false' - send_command_to_commissioner "sessionid --nwk other" 'DEAD00BEEF00CAFE": \d*' - send_command_to_commissioner "opdataset get active --nwk other" 'DEAD00BEEF00CAFE": {' - send_command_to_commissioner "commdataset get --nwk other" 'DEAD00BEEF00CAFE": {' + send_command_to_commissioner "sessionid --nwk other" '0xdead00beef00cafe": \d*' + send_command_to_commissioner "opdataset get active --nwk other" '0xdead00beef00cafe": {' + send_command_to_commissioner "commdataset get --nwk other" '0xdead00beef00cafe": {' send_command_to_commissioner "opdataset set securitypolicy 1000 ff --nwk other" send_command_to_commissioner "opdataset get pending --nwk other" send_command_to_commissioner "stop --nwk other" @@ -212,10 +212,10 @@ test_start_stop_mn_dom() { set -x send_command_to_commissioner "start --dom TestDomainName" - send_command_to_commissioner "active --dom TestDomainName" '2222222222222222": false' - send_command_to_commissioner "sessionid --dom TestDomainName" 'DEAD00BEEF00CAFE": \d*' - send_command_to_commissioner "opdataset get active --dom TestDomainName" 'DEAD00BEEF00CAFE": {' - send_command_to_commissioner "commdataset get --dom TestDomainName" 'DEAD00BEEF00CAFE": {' + send_command_to_commissioner "active --dom TestDomainName" '0x2222222222222222": false' + send_command_to_commissioner "sessionid --dom TestDomainName" '0xdead00beef00cafe": \d*' + send_command_to_commissioner "opdataset get active --dom TestDomainName" '0xdead00beef00cafe": {' + send_command_to_commissioner "commdataset get --dom TestDomainName" '0xdead00beef00cafe": {' send_command_to_commissioner "opdataset set securitypolicy 1000 ff --dom TestDomainName" send_command_to_commissioner "opdataset get pending --dom TestDomainName" send_command_to_commissioner "stop --dom TestDomainName" From 6561ae7eba25b4f7e491af83944561489db2970b Mon Sep 17 00:00:00 2001 From: Kangping Date: Fri, 17 May 2024 02:46:13 +0800 Subject: [PATCH 06/13] [android] cleanup Android sample app (#277) This commits cleans up / updates the existing MeshCoP functionality in the Android sample app: 1. Removes the local BorderAgentDatabase and data types by leveraging the Thread GMS SDK 2. Replaces the "discriminator" with the "id" mDNS TXT entry 3. Removes dead code such as `ThreadCommissionerServiceFactory` --- .../openthread_commissioner/app/build.gradle | 2 +- .../examples/qrcode/README.md | 3 + .../v=1&&eui=0000b57fffe15d68&&cc=J01NU5.png | Bin 0 -> 652 bytes .../service/build.gradle | 5 +- .../service/BorderAgentDatabaseTest.java | 67 --------- .../commissioner/service/BorderAgentDao.java | 61 -------- .../service/BorderAgentDatabase.java | 89 ------------ .../service/BorderAgentDiscoverer.java | 39 ++--- .../commissioner/service/BorderAgentInfo.java | 17 +-- .../service/BorderAgentRecord.java | 98 ------------- .../service/CommissionerUtils.java | 26 ++++ .../FetchCredentialDialogFragment.java | 9 +- .../commissioner/service/MeshcopFragment.java | 54 ++++--- .../commissioner/service/NetworkAdapter.java | 9 +- .../service/NetworkCredential.java | 33 ----- .../service/ScanQrCodeFragment.java | 3 - .../service/SelectNetworkFragment.java | 78 ++++++---- .../service/ThreadCommissionerService.java | 27 +--- .../ThreadCommissionerServiceFactory.java | 35 ----- .../ThreadCommissionerServiceImpl.java | 137 ++++++++---------- .../service/ThreadNetworkCredential.java | 78 ---------- .../service/src/main/res/values/styles.xml | 15 ++ 22 files changed, 222 insertions(+), 663 deletions(-) create mode 100644 android/openthread_commissioner/examples/qrcode/README.md create mode 100644 android/openthread_commissioner/examples/qrcode/v=1&&eui=0000b57fffe15d68&&cc=J01NU5.png delete mode 100644 android/openthread_commissioner/service/src/androidTest/java/io/openthread/commissioner/service/BorderAgentDatabaseTest.java delete mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDao.java delete mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDatabase.java delete mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentRecord.java delete mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/NetworkCredential.java delete mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerServiceFactory.java delete mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadNetworkCredential.java diff --git a/android/openthread_commissioner/app/build.gradle b/android/openthread_commissioner/app/build.gradle index f6f239a0..45b4ad1f 100644 --- a/android/openthread_commissioner/app/build.gradle +++ b/android/openthread_commissioner/app/build.gradle @@ -51,7 +51,7 @@ android { defaultConfig { applicationId "io.openthread.commissioner.app" - minSdkVersion 24 + minSdkVersion 26 targetSdkVersion 34 versionCode 1 versionName "0.0.1" diff --git a/android/openthread_commissioner/examples/qrcode/README.md b/android/openthread_commissioner/examples/qrcode/README.md new file mode 100644 index 00000000..4b3115d9 --- /dev/null +++ b/android/openthread_commissioner/examples/qrcode/README.md @@ -0,0 +1,3 @@ +# QR code + +- file `v=1&&eui=0000b57fffe15d68&&cc=J01NU5.png` is the Thread joiner device QR code which encodes the joiner EUI and PSKd as a text string (the content is `v=1&&eui=0000b57fffe15d68&&cc=J01NU5`) diff --git a/android/openthread_commissioner/examples/qrcode/v=1&&eui=0000b57fffe15d68&&cc=J01NU5.png b/android/openthread_commissioner/examples/qrcode/v=1&&eui=0000b57fffe15d68&&cc=J01NU5.png new file mode 100644 index 0000000000000000000000000000000000000000..9c0b71bf6b7791608526267ecad829c0ddb2a41e GIT binary patch literal 652 zcmV;70(1R|P)gII0{Fgq+rlu`N=lf&16#8+2X0#AKM?52Fr>g!eG>nyQVnKf5$BjPM99{^G9By z3kgXRl4g(KHyKn{8N+-S?ao!YVM#|q(u#CpdJ9Bs=@Dlm2@#*8VI>Jkb8=5qFzA^~ zLh?0oMz8ZN&GxGM+vF!9sX-)$W%6_qt5J81zAqI>NGgyNPHv$b-Q}Snt&QX$A!$MW zi1GzHcdu5Fkklid$=KS@@JzN|(k#g6G)O{HpGdj2+bJmzo?*|4zpc@RYe=TJKwt)E)60QlDg!c z6BSp@i$U})Q*D_ZOhQtbO!&(_-5IxZOU(<;B9lo-nvu&FbMh^R~icGd@%^8dj%!l7SB@&XF1ZnG;Jm6wm9JF_8pKiO6khCEwJd<-z m$=|mAm0KYpX+ju`e-}UNhrK&4d3Z7a0000> getAll(); - - @Query("SELECT * FROM border_agent_table WHERE discriminator=:discriminator LIMIT 1") - BorderAgentRecord getBorderAgent(@NonNull String discriminator); - - @Query( - "SELECT * FROM border_agent_table WHERE network_name=:networkName AND extended_pan_id=:extendedPanId") - List getBorderAgents( - @NonNull String networkName, @NonNull byte[] extendedPanId); - - @Insert(onConflict = OnConflictStrategy.IGNORE) - void insert(BorderAgentRecord borderAgentRecord); - - @Query("DELETE FROM border_agent_table WHERE discriminator=:discriminator") - void delete(@NonNull String discriminator); - - @Query("DELETE FROM border_agent_table") - void deleteAll(); -} diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDatabase.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDatabase.java deleted file mode 100644 index c8b7d87f..00000000 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDatabase.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2020, The OpenThread Commissioner Authors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -package io.openthread.commissioner.service; - -import androidx.annotation.NonNull; -import androidx.room.Database; -import androidx.room.Room; -import androidx.room.RoomDatabase; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -@Database( - entities = {BorderAgentRecord.class}, - version = 1, - exportSchema = false) -abstract class BorderAgentDatabase extends RoomDatabase { - - abstract BorderAgentDao borderAgentDao(); - - private static volatile BorderAgentDatabase INSTANCE; - private static final int NUMBER_OF_THREADS = 2; - - static final ExecutorService executor = Executors.newFixedThreadPool(NUMBER_OF_THREADS); - - public static synchronized BorderAgentDatabase getDatabase() { - if (INSTANCE == null) { - INSTANCE = - Room.databaseBuilder( - CommissionerServiceApp.getContext(), - BorderAgentDatabase.class, - "network_credential_database") - .build(); - } - return INSTANCE; - } - - public CompletableFuture getBorderAgent(@NonNull String discriminator) { - CompletableFuture future = - CompletableFuture.supplyAsync(() -> borderAgentDao().getBorderAgent(discriminator)); - return future; - } - - public CompletableFuture insertBorderAgent(@NonNull BorderAgentRecord borderAgentRecord) { - CompletableFuture future = - CompletableFuture.runAsync( - () -> { - borderAgentDao().insert(borderAgentRecord); - }, - executor); - return future; - } - - public CompletableFuture deleteBorderAgent(@NonNull String discriminator) { - CompletableFuture future = - CompletableFuture.runAsync( - () -> { - borderAgentDao().delete(discriminator); - }, - executor); - return future; - } -} diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDiscoverer.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDiscoverer.java index f63bd587..6e4214d1 100644 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDiscoverer.java +++ b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDiscoverer.java @@ -34,6 +34,7 @@ import android.net.nsd.NsdServiceInfo; import android.net.wifi.WifiManager; import android.util.Log; +import androidx.annotation.Nullable; import androidx.annotation.RequiresPermission; import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; @@ -47,7 +48,7 @@ public class BorderAgentDiscoverer implements NsdManager.DiscoveryListener { private static final String TAG = BorderAgentDiscoverer.class.getSimpleName(); private static final String SERVICE_TYPE = "_meshcop._udp"; - private static final String KEY_DISCRIMINATOR = "discriminator"; + private static final String KEY_ID = "id"; private static final String KEY_NETWORK_NAME = "nn"; private static final String KEY_EXTENDED_PAN_ID = "xp"; @@ -62,9 +63,10 @@ public class BorderAgentDiscoverer implements NsdManager.DiscoveryListener { private boolean isScanning = false; public interface BorderAgentListener { + void onBorderAgentFound(BorderAgentInfo borderAgentInfo); - void onBorderAgentLost(String discriminator); + void onBorderAgentLost(byte[] id); } @RequiresPermission(permission.INTERNET) @@ -182,10 +184,10 @@ public void onServiceFound(NsdServiceInfo nsdServiceInfo) { @Override public void onServiceLost(NsdServiceInfo nsdServiceInfo) { - String discriminator = getBorderAgentDiscriminator(nsdServiceInfo); - if (discriminator != null) { - Log.d(TAG, "a Border Agent service is gone"); - borderAgentListener.onBorderAgentLost(discriminator); + byte[] id = getBorderAgentId(nsdServiceInfo); + if (id != null) { + Log.d(TAG, "a Border Agent service is gone: " + nsdServiceInfo.getServiceName()); + borderAgentListener.onBorderAgentLost(id); } } @@ -199,40 +201,29 @@ public void onStopDiscoveryFailed(String serviceType, int errorCode) { Log.d(TAG, "stop discovering Border Agent failed: " + errorCode); } + @Nullable private BorderAgentInfo getBorderAgentInfo(NsdServiceInfo serviceInfo) { Map attrs = serviceInfo.getAttributes(); - - // Use the host address as default discriminator. - String discriminator = serviceInfo.getHost().getHostAddress(); - - if (attrs.containsKey(KEY_DISCRIMINATOR)) { - discriminator = new String(attrs.get(KEY_DISCRIMINATOR)); - } + byte[] id = getBorderAgentId(serviceInfo); if (!attrs.containsKey(KEY_NETWORK_NAME) || !attrs.containsKey(KEY_EXTENDED_PAN_ID)) { return null; } return new BorderAgentInfo( - discriminator, + id, new String(attrs.get(KEY_NETWORK_NAME)), attrs.get(KEY_EXTENDED_PAN_ID), serviceInfo.getHost(), serviceInfo.getPort()); } - private String getBorderAgentDiscriminator(NsdServiceInfo serviceInfo) { + @Nullable + private byte[] getBorderAgentId(NsdServiceInfo serviceInfo) { Map attrs = serviceInfo.getAttributes(); - - if (attrs.containsKey(KEY_DISCRIMINATOR)) { - return new String(attrs.get(KEY_DISCRIMINATOR)); - } - - if (serviceInfo.getHost() != null) { - // Use the host address as default discriminator. - return serviceInfo.getHost().getHostAddress(); + if (attrs.containsKey(KEY_ID)) { + return attrs.get(KEY_ID).clone(); } - return null; } } diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentInfo.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentInfo.java index c60bc9a7..0a9babed 100644 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentInfo.java +++ b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentInfo.java @@ -35,27 +35,28 @@ import java.net.UnknownHostException; public class BorderAgentInfo implements Parcelable { - public String discriminator; + + public byte[] id; public String networkName; public byte[] extendedPanId; public InetAddress host; public int port; public BorderAgentInfo( - @NonNull String discriminator, + @NonNull byte[] id, @NonNull String networkName, @NonNull byte[] extendedPanId, @NonNull InetAddress host, @NonNull int port) { - this.discriminator = discriminator; + this.id = id.clone(); this.networkName = networkName; - this.extendedPanId = extendedPanId; + this.extendedPanId = extendedPanId.clone(); this.host = host; this.port = port; } protected BorderAgentInfo(Parcel in) { - discriminator = in.readString(); + id = in.createByteArray(); networkName = in.readString(); extendedPanId = in.createByteArray(); try { @@ -67,7 +68,7 @@ protected BorderAgentInfo(Parcel in) { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeString(discriminator); + dest.writeByteArray(id); dest.writeString(networkName); dest.writeByteArray(extendedPanId); dest.writeByteArray(host.getAddress()); @@ -79,10 +80,6 @@ public int describeContents() { return 0; } - public boolean equals(BorderAgentInfo other) { - return this.discriminator.equals(other.discriminator); - } - public static final Creator CREATOR = new Creator() { @Override diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentRecord.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentRecord.java deleted file mode 100644 index 107a8ea9..00000000 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentRecord.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2020, The OpenThread Commissioner Authors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -package io.openthread.commissioner.service; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.room.ColumnInfo; -import androidx.room.Entity; -import androidx.room.PrimaryKey; - -@Entity(tableName = "border_agent_table") -public class BorderAgentRecord { - - @PrimaryKey - @NonNull - @ColumnInfo(name = "discriminator") - private String discriminator; - - @NonNull - @ColumnInfo(name = "network_name") - private String networkName; - - @NonNull - @ColumnInfo(name = "extended_pan_id", typeAffinity = ColumnInfo.BLOB) - private byte[] extendedPanId; - - @NonNull - @ColumnInfo(name = "pskc", typeAffinity = ColumnInfo.BLOB) - private byte[] pskc; - - @Nullable - @ColumnInfo(name = "active_operational_dataset", typeAffinity = ColumnInfo.BLOB) - private byte[] activeOperationalDataset; - - public BorderAgentRecord( - @NonNull String discriminator, - @NonNull String networkName, - @NonNull byte[] extendedPanId, - @NonNull byte[] pskc, - @Nullable byte[] activeOperationalDataset) { - this.discriminator = discriminator; - this.networkName = networkName; - this.extendedPanId = extendedPanId; - this.pskc = pskc; - this.activeOperationalDataset = activeOperationalDataset; - } - - @NonNull - public String getDiscriminator() { - return discriminator; - } - - @NonNull - public String getNetworkName() { - return networkName; - } - - @NonNull - public byte[] getExtendedPanId() { - return extendedPanId; - } - - @NonNull - public byte[] getPskc() { - return pskc; - } - - @Nullable - public byte[] getActiveOperationalDataset() { - return activeOperationalDataset; - } -} diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/CommissionerUtils.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/CommissionerUtils.java index a51f4097..b3174888 100644 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/CommissionerUtils.java +++ b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/CommissionerUtils.java @@ -29,6 +29,9 @@ package io.openthread.commissioner.service; import androidx.annotation.Nullable; +import androidx.concurrent.futures.CallbackToFutureAdapter; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; import io.openthread.commissioner.ByteArray; public class CommissionerUtils { @@ -76,4 +79,27 @@ public static String getHexString(@Nullable byte[] byteArray) { public static String getHexString(ByteArray byteArray) { return getHexString(getByteArray(byteArray)); } + + /** Converts a {@link Task} to a {@link ListenableFuture}. */ + public static ListenableFuture toListenableFuture(Task task) { + return CallbackToFutureAdapter.getFuture( + completer -> { + task.addOnCompleteListener( + completedTask -> { + if (completedTask.isCanceled()) { + completer.setCancelled(); + } else if (completedTask.isSuccessful()) { + completer.set(completedTask.getResult()); + } else { + Exception e = completedTask.getException(); + if (e != null) { + completer.setException(e); + } else { + throw new IllegalStateException(); + } + } + }); + return "toListenableFuture"; + }); + } } diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/FetchCredentialDialogFragment.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/FetchCredentialDialogFragment.java index 58b6c6f9..7331e61b 100644 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/FetchCredentialDialogFragment.java +++ b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/FetchCredentialDialogFragment.java @@ -39,6 +39,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; +import com.google.android.gms.threadnetwork.ThreadNetworkCredentials; public class FetchCredentialDialogFragment extends DialogFragment implements DialogInterface.OnClickListener { @@ -50,12 +51,14 @@ public class FetchCredentialDialogFragment extends DialogFragment BorderAgentInfo borderAgentInfo; byte[] pskc; - private ThreadNetworkCredential credential; + private ThreadNetworkCredentials credentials; public interface CredentialListener { + void onCancelClick(FetchCredentialDialogFragment fragment); - void onConfirmClick(FetchCredentialDialogFragment fragment, ThreadNetworkCredential credential); + void onConfirmClick( + FetchCredentialDialogFragment fragment, ThreadNetworkCredentials credentials); } public FetchCredentialDialogFragment( @@ -105,7 +108,7 @@ public void onStop() { @Override public void onClick(DialogInterface dialogInterface, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { - credentialListener.onConfirmClick(this, credential); + credentialListener.onConfirmClick(this, credentials); } else { stopFetching(); credentialListener.onCancelClick(this); diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/MeshcopFragment.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/MeshcopFragment.java index f36d3700..2ba0eb6a 100644 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/MeshcopFragment.java +++ b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/MeshcopFragment.java @@ -40,8 +40,11 @@ import android.widget.ProgressBar; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; -import java.util.concurrent.CompletableFuture; +import com.google.common.util.concurrent.FluentFuture; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.ListenableFuture; public class MeshcopFragment extends Fragment implements ThreadCommissionerServiceImpl.IntermediateStateCallback { @@ -55,18 +58,17 @@ public class MeshcopFragment extends Fragment ImageView doneImage; ImageView errorImage; - @NonNull private FragmentCallback meshcopCallback; + @NonNull private final FragmentCallback meshcopCallback; - @NonNull private ThreadNetworkInfoHolder networkInfoHolder; + @NonNull private final ThreadNetworkInfoHolder networkInfoHolder; - @NonNull private byte[] pskc; + @NonNull private final byte[] pskc; - @NonNull private JoinerDeviceInfo joinerDeviceInfo; + @NonNull private final JoinerDeviceInfo joinerDeviceInfo; - private ThreadCommissionerServiceImpl commissionerService = - new ThreadCommissionerServiceImpl(this); - - private CompletableFuture commissionFuture; + private final ThreadCommissionerServiceImpl commissionerService = + ThreadCommissionerServiceImpl.newInstance(this); + private ListenableFuture commissionFuture; public MeshcopFragment( @NonNull FragmentCallback meshcopCallback, @@ -127,25 +129,21 @@ private void startMeshcop() { showInProgress("Petitioning..."); commissionFuture = - commissionerService - .commissionJoinerDevice(borderAgentInfo, pskc, joinerDeviceInfo) - .thenRun( - () -> { - new Handler(Looper.getMainLooper()) - .post( - () -> { - showCommissionDone(true, "Commission Succeed"); - }); - }) - .exceptionally( - ex -> { - new Handler(Looper.getMainLooper()) - .post( - () -> { - showCommissionDone(false, ex.getMessage()); - }); - return null; - }); + commissionerService.commissionJoinerDevice(borderAgentInfo, pskc, joinerDeviceInfo); + FluentFuture.from(commissionFuture) + .addCallback( + new FutureCallback() { + @Override + public void onSuccess(Void result) { + showCommissionDone(true, "Commission Succeed"); + } + + @Override + public void onFailure(Throwable t) { + showCommissionDone(false, t.getMessage()); + } + }, + ContextCompat.getMainExecutor(getActivity())); } private void stopMeshcop() { diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/NetworkAdapter.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/NetworkAdapter.java index 96a220a6..ebb25962 100644 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/NetworkAdapter.java +++ b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/NetworkAdapter.java @@ -41,6 +41,7 @@ import java.util.Vector; public class NetworkAdapter extends BaseAdapter implements BorderAgentListener { + private Vector networks; private LayoutInflater inflater; @@ -68,10 +69,10 @@ public void addBorderAgent(BorderAgentInfo borderAgent) { new Handler(Looper.getMainLooper()).post(() -> notifyDataSetChanged()); } - public void removeBorderAgent(String lostBorderAgentDisciminator) { + public void removeBorderAgent(byte[] lostBorderAgentId) { for (ThreadNetworkInfoHolder networkInfoHolder : networks) { for (BorderAgentInfo borderAgent : networkInfoHolder.getBorderAgents()) { - if (borderAgent.discriminator.equals(lostBorderAgentDisciminator)) { + if (Arrays.equals(borderAgent.id, lostBorderAgentId)) { networkInfoHolder.getBorderAgents().remove(borderAgent); if (networkInfoHolder.getBorderAgents().isEmpty()) { networks.remove(networkInfoHolder); @@ -119,7 +120,7 @@ public void onBorderAgentFound(BorderAgentInfo borderAgentInfo) { } @Override - public void onBorderAgentLost(String discriminator) { - removeBorderAgent(discriminator); + public void onBorderAgentLost(byte[] borderAgentId) { + removeBorderAgent(borderAgentId); } } diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/NetworkCredential.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/NetworkCredential.java deleted file mode 100644 index ea37c923..00000000 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/NetworkCredential.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2020, The OpenThread Commissioner Authors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -package io.openthread.commissioner.service; - -public interface NetworkCredential { - byte[] getEncoded(); -} diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ScanQrCodeFragment.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ScanQrCodeFragment.java index e2020cd7..229a6003 100644 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ScanQrCodeFragment.java +++ b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ScanQrCodeFragment.java @@ -56,9 +56,6 @@ public class ScanQrCodeFragment extends Fragment implements Detector.Processor() { + @Override + public void onSuccess(ThreadNetworkCredentials credentials) { + if (credentials != null) { + networkInfoCallback.onNetworkSelected(selectedNetwork, credentials.getPskc()); + } else { + // Ask the user to input Commissioner password. + new InputNetworkPasswordDialogFragment(SelectNetworkFragment.this) + .show( + getParentFragmentManager(), + InputNetworkPasswordDialogFragment.class.getSimpleName()); + } + } + + @Override + public void onFailure(Throwable t) { + Log.e(TAG, "Failed to retrieve Thread network credentials from GMS", t); + showAlertDialog(t.getMessage()); + } + }, + ContextCompat.getMainExecutor(getActivity())); + } + + private void showAlertDialog(String message) { + new MaterialAlertDialogBuilder(getActivity(), R.style.ThreadNetworkAlertTheme) + .setMessage(message) + .setPositiveButton( + "OK", + ((dialog, which) -> { + networkInfoCallback.onMeshcopResult(Activity.RESULT_CANCELED); + })) + .show(); } @Override @@ -230,7 +252,7 @@ public void onCancelClick(FetchCredentialDialogFragment fragment) { @Override public void onConfirmClick( - FetchCredentialDialogFragment fragment, ThreadNetworkCredential credential) { + FetchCredentialDialogFragment fragment, ThreadNetworkCredentials credentials) { // TODO: } } diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerService.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerService.java index bdfc35fd..87add5fc 100644 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerService.java +++ b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerService.java @@ -29,32 +29,17 @@ package io.openthread.commissioner.service; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import java.util.concurrent.CompletableFuture; +import com.google.android.gms.threadnetwork.ThreadNetworkCredentials; +import com.google.common.util.concurrent.ListenableFuture; public interface ThreadCommissionerService { - // This method returns Credential of a given Thread Network. - // If the Commissioner Service doesn't possess the Network - // Credentials already, it will fetch the Credentials from - // a Border Agent (assisting device) using the Thread - // Commissioning protocol. - // - // The pskc is used to securely connect to the Border Agent device. - // If no pskc is given, the user will be asked to input it. - // The Network Credentials will be saved in the Commissioner - // Service before returning. - CompletableFuture fetchThreadNetworkCredential( - @NonNull BorderAgentInfo borderAgentInfo, @Nullable byte[] pskc); - - // This method returns Credential of a given Thread Network stored in the database on the phone. - CompletableFuture getThreadNetworkCredential( + /** Returns Credential of a given Thread Network stored in the database on the phone. */ + ListenableFuture getThreadNetworkCredentials( @NonNull BorderAgentInfo borderAgentInfo); - // This method deletes Credential of a given Thread Network stored in the database on the phone. - CompletableFuture deleteThreadNetworkCredential(@NonNull BorderAgentInfo borderAgentInfo); - - CompletableFuture commissionJoinerDevice( + /** Securely adds a new Thread joiner device into the Thread network via MeshCoP. */ + ListenableFuture commissionJoinerDevice( @NonNull BorderAgentInfo borderAgentInfo, @NonNull byte[] pskc, @NonNull JoinerDeviceInfo joinerDeviceInfo); diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerServiceFactory.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerServiceFactory.java deleted file mode 100644 index d42550a1..00000000 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerServiceFactory.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2020, The OpenThread Commissioner Authors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -package io.openthread.commissioner.service; - -class ThreadCommissionerServiceFactory { - public static ThreadCommissionerService getCommissionerService() { - return new ThreadCommissionerServiceImpl(null); - } -} diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerServiceImpl.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerServiceImpl.java index da9f34bd..e2490118 100644 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerServiceImpl.java +++ b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerServiceImpl.java @@ -32,6 +32,14 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.google.android.gms.threadnetwork.ThreadBorderAgent; +import com.google.android.gms.threadnetwork.ThreadNetwork; +import com.google.android.gms.threadnetwork.ThreadNetworkClient; +import com.google.android.gms.threadnetwork.ThreadNetworkCredentials; +import com.google.common.util.concurrent.FluentFuture; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; import io.openthread.commissioner.ByteArray; import io.openthread.commissioner.ChannelMask; import io.openthread.commissioner.Commissioner; @@ -43,14 +51,15 @@ import java.math.BigInteger; import java.net.Inet6Address; import java.net.InetAddress; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; public class ThreadCommissionerServiceImpl extends CommissionerHandler implements ThreadCommissionerService { public interface IntermediateStateCallback { + void onPetitioned(); void onJoinerRequest(@NonNull byte[] joinerId); @@ -60,93 +69,64 @@ public interface IntermediateStateCallback { private static final int SECONDS_WAIT_FOR_JOINER = 60; + private final ThreadNetworkClient threadNetworkClient; + private final Executor executor; @Nullable private IntermediateStateCallback intermediateStateCallback; - @NonNull private BorderAgentDatabase borderAgentDatabase = BorderAgentDatabase.getDatabase(); - @Nullable private JoinerDeviceInfo curJoinerInfo; private ConditionVariable curJoinerCommissioned = new ConditionVariable(); - public ThreadCommissionerServiceImpl( + public static ThreadCommissionerServiceImpl newInstance( + @Nullable IntermediateStateCallback intermediateStateCallback) { + return new ThreadCommissionerServiceImpl( + ThreadNetwork.getClient(CommissionerServiceApp.getContext()), + Executors.newSingleThreadExecutor(), + intermediateStateCallback); + } + + private ThreadCommissionerServiceImpl( + ThreadNetworkClient threadNetworkClient, + Executor executor, @Nullable IntermediateStateCallback intermediateStateCallback) { + this.threadNetworkClient = threadNetworkClient; + this.executor = executor; this.intermediateStateCallback = intermediateStateCallback; } @Override - public CompletableFuture commissionJoinerDevice( + public ListenableFuture commissionJoinerDevice( @NonNull BorderAgentInfo borderAgentInfo, @NonNull byte[] pskc, @NonNull JoinerDeviceInfo joinerDeviceInfo) { - CompletableFuture future = - CompletableFuture.runAsync( - () -> { - try { - doCommissionJoinerDevice( - borderAgentInfo, pskc, joinerDeviceInfo, SECONDS_WAIT_FOR_JOINER); - } catch (ThreadCommissionerException e) { - throw new CompletionException(e); - } - }); - return future; - } - - @Override - public CompletableFuture fetchThreadNetworkCredential( - @NonNull BorderAgentInfo borderAgentInfo, @Nullable byte[] pskc) { - return getThreadNetworkCredential(borderAgentInfo) - .thenApply( - credential -> { - if (credential != null) { - return credential; - } - - try { - byte[] activeDataset = doFetchActiveDataset(borderAgentInfo, pskc); - return new ThreadNetworkCredential(activeDataset); - } catch (ThreadCommissionerException e) { - throw new CompletionException(e); - } - }); - } - - @Override - public CompletableFuture getThreadNetworkCredential( - @NonNull BorderAgentInfo borderAgentInfo) { - return getBorderAgentRecord(borderAgentInfo) - .thenApply( - borderAgentRecord -> { - if (borderAgentRecord == null - || borderAgentRecord.getActiveOperationalDataset() == null) { - return null; - } - return new ThreadNetworkCredential(borderAgentRecord.getActiveOperationalDataset()); - }); - } - - CompletableFuture getBorderAgentRecord( - @NonNull BorderAgentInfo borderAgentInfo) { - return borderAgentDatabase.getBorderAgent(borderAgentInfo.discriminator); + return Futures.submitAsync( + () -> { + try { + doCommissionJoinerDevice( + borderAgentInfo, pskc, joinerDeviceInfo, SECONDS_WAIT_FOR_JOINER); + return Futures.immediateVoidFuture(); + } catch (ThreadCommissionerException ex) { + return Futures.immediateFailedFuture(ex); + } + }, + executor); } @Override - public CompletableFuture deleteThreadNetworkCredential( + public ListenableFuture getThreadNetworkCredentials( @NonNull BorderAgentInfo borderAgentInfo) { - return borderAgentDatabase.deleteBorderAgent(borderAgentInfo.discriminator); + return FluentFuture.from( + CommissionerUtils.toListenableFuture( + threadNetworkClient.getCredentialsByBorderAgent( + ThreadBorderAgent.newBuilder(borderAgentInfo.id).build()))) + .transform(result -> result.getCredentials(), MoreExecutors.directExecutor()); } - // This method adds given Thread Network Credential into database on the phone. - private CompletableFuture addThreadNetworkCredential( - @NonNull BorderAgentInfo borderAgentInfo, - @NonNull byte[] pskc, - @Nullable ThreadNetworkCredential networkCredential) { - BorderAgentRecord borderAgentRecord = - new BorderAgentRecord( - borderAgentInfo.discriminator, - borderAgentInfo.networkName, - borderAgentInfo.extendedPanId, - pskc, - networkCredential == null ? null : networkCredential.getEncoded()); - return borderAgentDatabase.insertBorderAgent(borderAgentRecord); + /** Adds given Thread Network Credential into database on the phone. */ + private ListenableFuture addThreadNetworkCredentials( + BorderAgentInfo borderAgentInfo, ThreadNetworkCredentials credentials) { + return CommissionerUtils.toListenableFuture( + threadNetworkClient.addCredentials( + ThreadBorderAgent.newBuilder(borderAgentInfo.id).build(), credentials)); } private void doCommissionJoinerDevice( @@ -177,8 +157,13 @@ private void doCommissionJoinerDevice( nativeCommissioner.petition( existingCommissionerId, borderAgentInfo.host.getHostAddress(), borderAgentInfo.port)); - // Save PSKc for current Border Agent once we have successfully connected to it. - addThreadNetworkCredential(borderAgentInfo, pskc, null).get(); + // Retrieves active dataset and saves it to GMS Core + ByteArray rawActiveDataset = new ByteArray(); + throwIfFail(nativeCommissioner.getRawActiveDataset(rawActiveDataset, 0xFFFF)); + ThreadNetworkCredentials credentials = + ThreadNetworkCredentials.fromActiveOperationalDataset( + CommissionerUtils.getByteArray(rawActiveDataset)); + addThreadNetworkCredentials(borderAgentInfo, credentials).get(); if (intermediateStateCallback != null) { intermediateStateCallback.onPetitioned(); @@ -235,8 +220,6 @@ private byte[] doFetchActiveDataset( getBorderAgentAddress(borderAgentInfo), borderAgentInfo.port)); - addThreadNetworkCredential(borderAgentInfo, pskc, null).get(); - if (intermediateStateCallback != null) { intermediateStateCallback.onPetitioned(); } @@ -245,10 +228,6 @@ private byte[] doFetchActiveDataset( ByteArray rawActiveDataset = new ByteArray(); throwIfFail(nativeCommissioner.getRawActiveDataset(rawActiveDataset, 0xFFFF)); return CommissionerUtils.getByteArray(rawActiveDataset); - } catch (InterruptedException e) { - throw new ThreadCommissionerException(ErrorCode.kUnknown, e.getMessage()); - } catch (ExecutionException e) { - throw new ThreadCommissionerException(ErrorCode.kUnknown, e.getMessage()); } finally { nativeCommissioner.resign(); } @@ -320,7 +299,7 @@ public void onEnergyReport(String aPeerAddr, ChannelMask aChannelMask, ByteArray @Override public void onDatasetChanged() { - Log.d(TAG, "Thread Network Dataset chanaged"); + Log.d(TAG, "Thread Network Dataset changed"); } private ByteArray getCurJoinerId() { diff --git a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadNetworkCredential.java b/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadNetworkCredential.java deleted file mode 100644 index 3d09edd3..00000000 --- a/android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadNetworkCredential.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2020, The OpenThread Commissioner Authors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -package io.openthread.commissioner.service; - -import android.os.Parcel; -import android.os.Parcelable; -import androidx.annotation.NonNull; - -public class ThreadNetworkCredential implements NetworkCredential, Parcelable { - - @NonNull private final byte[] activeOperationalDataset; - - public ThreadNetworkCredential(@NonNull byte[] activeOperationalDataset) { - this.activeOperationalDataset = activeOperationalDataset; - } - - protected ThreadNetworkCredential(Parcel in) { - activeOperationalDataset = in.createByteArray(); - } - - public static final Creator CREATOR = - new Creator() { - @Override - public ThreadNetworkCredential createFromParcel(Parcel in) { - return new ThreadNetworkCredential(in); - } - - @Override - public ThreadNetworkCredential[] newArray(int size) { - return new ThreadNetworkCredential[size]; - } - }; - - public byte[] getActiveOperationalDataset() { - return activeOperationalDataset; - } - - @Override - public byte[] getEncoded() { - return activeOperationalDataset; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel parcel, int i) { - parcel.writeByteArray(activeOperationalDataset); - } -} diff --git a/android/openthread_commissioner/service/src/main/res/values/styles.xml b/android/openthread_commissioner/service/src/main/res/values/styles.xml index 3641696d..9b196667 100644 --- a/android/openthread_commissioner/service/src/main/res/values/styles.xml +++ b/android/openthread_commissioner/service/src/main/res/values/styles.xml @@ -10,4 +10,19 @@ + + + + From 397114d1be4ef610483d04bec5503b217db9b4d6 Mon Sep 17 00:00:00 2001 From: ZhangLe2016 <156590889+ZhangLe2016@users.noreply.github.com> Date: Tue, 21 May 2024 13:24:09 +0800 Subject: [PATCH 07/13] [log] add a new logging region for network diagnostic functionality (#268) --- src/common/logging.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/common/logging.hpp b/src/common/logging.hpp index 4d659267..52bc23d3 100644 --- a/src/common/logging.hpp +++ b/src/common/logging.hpp @@ -51,6 +51,7 @@ #define LOG_REGION_JOB_MANAGER "job-manager" #define LOG_REGION_JOB "job" #define LOG_REGION_SECURITY_MATERIALS "security-materials" +#define LOG_REGION_MESHDIAG "meshdiag" #define LOG(aLevel, aRegion, aFmt, ...) \ do \ From 1913f477c0ef1b056e4c4477e4996b7ef6b8ec84 Mon Sep 17 00:00:00 2001 From: ZhangLe2016 <156590889+ZhangLe2016@users.noreply.github.com> Date: Fri, 24 May 2024 02:09:28 +0800 Subject: [PATCH 08/13] [uri] add DIAG_GET URIs for disgnostic APIs (#267) In order to enable libotcommissioner.jar to support the diagnostic commands, it is necessary to integrate all diagnostic URIs into the uri module. --- src/library/uri.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/library/uri.hpp b/src/library/uri.hpp index c528ba9a..d8535eb9 100644 --- a/src/library/uri.hpp +++ b/src/library/uri.hpp @@ -75,6 +75,14 @@ static const char *const kJoinEnt = "/c/je"; static const char *const kJoinFin = "/c/jf"; static const char *const kJoinApp = "/c/ja"; +/* + * Thread diagnostic URIs + */ +static const char *const kDiagGet = "/d/dg"; +static const char *const kDiagGetQuery = "/d/dq"; +static const char *const kDiagGetAns = "/d/da"; +static const char *const kDiagRst = "/d/dr"; + /* * Thread Network Layer URIs */ From 62a1b82cd6350c359e9482126c8c9fbe561e3f86 Mon Sep 17 00:00:00 2001 From: ZhangLe2016 <156590889+ZhangLe2016@users.noreply.github.com> Date: Thu, 20 Jun 2024 07:50:15 +0800 Subject: [PATCH 09/13] [udp-proxy] set local port to dedicated port number(:mm) for udp proxy transaction (#279) Currently, while the commissioner is transmitting udp_tx messages, the UDP source port is provided by the `DtlsSession` interface. This value is randomly generated. However, the CoAP layer on the border router side performs checks on the received udp_tx port to ensure that the destination UDP port used to outgoing messages matches the source port of the received messages. This leads to the commissioner's ACK messages not being processed, causing the BR side to repeatedly retransmit the same udp_rx message. To resolve this issue, we use the default MM port as the only supported destination port for UDP_RX messages. --- include/commissioner/defines.hpp | 5 +++++ src/library/commissioner_impl.cpp | 2 -- src/library/udp_proxy.cpp | 10 +++++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/commissioner/defines.hpp b/include/commissioner/defines.hpp index c3fe5614..d619f850 100644 --- a/include/commissioner/defines.hpp +++ b/include/commissioner/defines.hpp @@ -123,6 +123,11 @@ static constexpr uint16_t kDefaultAeUdpPort = 1001; */ static constexpr uint16_t kDefaultNmkpUdpPort = 1002; +/** + * The default management UDP Port used by TMF transaction in Thread devices. + */ +static constexpr uint16_t kDefaultMmPort = 61631; + /** * If using radio 915Mhz. Default radio freq of Thread is 2.4Ghz. * diff --git a/src/library/commissioner_impl.cpp b/src/library/commissioner_impl.cpp index 57370d5a..94404161 100644 --- a/src/library/commissioner_impl.cpp +++ b/src/library/commissioner_impl.cpp @@ -70,8 +70,6 @@ namespace commissioner { static constexpr uint16_t kLeaderAloc16 = 0xFC00; static constexpr uint16_t kPrimaryBbrAloc16 = 0xFC38; -static constexpr uint16_t kDefaultMmPort = 61631; - static constexpr uint32_t kMinKeepAliveInterval = 30; static constexpr uint32_t kMaxKeepAliveInterval = 45; diff --git a/src/library/udp_proxy.cpp b/src/library/udp_proxy.cpp index e6abf62a..77a546d9 100644 --- a/src/library/udp_proxy.cpp +++ b/src/library/udp_proxy.cpp @@ -81,7 +81,8 @@ Error ProxyEndpoint::Send(const ByteArray &aRequest, MessageSubType aSubType) VerifyOrExit(mBrClient.IsConnected(), error = ERROR_INVALID_STATE("not connected to the border agent")); - utils::Encode(udpPayload, mBrClient.GetDtlsSession().GetLocalPort()); + // set the source port to default mamagement port for UDP_Tx message + utils::Encode(udpPayload, kDefaultMmPort); utils::Encode(udpPayload, GetPeerPort()); udpPayload.insert(udpPayload.end(), aRequest.begin(), aRequest.end()); @@ -151,6 +152,7 @@ void ProxyClient::HandleUdpRx(const coap::Request &aUdpRx) Error error; Address peerAddr; uint16_t peerPort; + uint16_t destPort; tlv::TlvPtr srcAddr = nullptr; tlv::TlvPtr udpEncap = nullptr; @@ -163,6 +165,12 @@ void ProxyClient::HandleUdpRx(const coap::Request &aUdpRx) peerPort = utils::Decode(udpEncap->GetValue()); + // get the dest port from the UDP_Rx message + destPort = utils::Decode(&udpEncap->GetValue()[2], sizeof(uint16_t)); + VerifyOrExit(destPort == kDefaultMmPort, + ERROR_UNIMPLEMENTED("dropping UDP_RX.ntf message to port {}: only port {} is supported", destPort, + kDefaultMmPort)); + mEndpoint.SetPeerAddr(peerAddr); mEndpoint.SetPeerPort(peerPort); From 384ec58f1b39fe1ac3161e4ecbf4123adf06bdfe Mon Sep 17 00:00:00 2001 From: Kangping Date: Mon, 24 Jun 2024 23:21:51 +0800 Subject: [PATCH 10/13] [thread] make Joiner Provisioning URL independently optional (#285) --- src/library/joiner_session.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/library/joiner_session.cpp b/src/library/joiner_session.cpp index b2063877..cd34ee6b 100644 --- a/src/library/joiner_session.cpp +++ b/src/library/joiner_session.cpp @@ -187,11 +187,12 @@ void JoinerSession::HandleJoinFin(const coap::Request &aJoinFin) if (auto provisioningUrlTlv = tlvSet[tlv::Type::kProvisioningURL]) { - auto vendorDataTlv = tlvSet[tlv::Type::kVendorData]; - VerifyOrExit(vendorDataTlv != nullptr, error = ERROR_BAD_FORMAT("no valid Vendor Data TLV found")); - provisioningUrl = provisioningUrlTlv->GetValueAsString(); - vendorData = vendorDataTlv->GetValue(); + } + + if (auto vendorDataTlv = tlvSet[tlv::Type::kVendorData]) + { + vendorData = vendorDataTlv->GetValue(); } LOG_INFO(LOG_REGION_JOINER_SESSION, From af15906519445c2df0f81a1789426cf232f5716b Mon Sep 17 00:00:00 2001 From: Kangping Date: Tue, 9 Jul 2024 11:03:36 +0800 Subject: [PATCH 11/13] [coap] handle zero coap token length (#286) There could be potential out of bound error if the token length in CoAP header is zero (`&aBuf[offset]` could be referring to the next element after the end of the buffer). Note that the added test can pass without the fix in coap.cpp but it's probably because the toolchain has some optimization to avoid such issues... --- src/library/coap.cpp | 11 +++++++---- src/library/coap_test.cpp | 12 ++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/library/coap.cpp b/src/library/coap.cpp index 0bafc985..e64957f3 100644 --- a/src/library/coap.cpp +++ b/src/library/coap.cpp @@ -328,10 +328,13 @@ Error Message::Deserialize(Header &aHeader, const ByteArray &aBuf, size_t &aOffs header.mMessageId = aBuf[offset++]; header.mMessageId = (header.mMessageId << 8) | aBuf[offset++]; - VerifyOrExit(offset + header.mTokenLength <= aBuf.size(), - error = ERROR_BAD_FORMAT("premature end of CoAP message header")); - memcpy(header.mToken, &aBuf[offset], std::min(header.mTokenLength, kMaxTokenLength)); - offset += header.mTokenLength; + if (header.mTokenLength != 0) + { + VerifyOrExit(offset + header.mTokenLength <= aBuf.size(), + error = ERROR_BAD_FORMAT("premature end of CoAP message header")); + memcpy(header.mToken, &aBuf[offset], std::min(header.mTokenLength, kMaxTokenLength)); + offset += header.mTokenLength; + } aHeader = header; aOffset = offset; diff --git a/src/library/coap_test.cpp b/src/library/coap_test.cpp index b4d9ed10..7dc1b1f3 100644 --- a/src/library/coap_test.cpp +++ b/src/library/coap_test.cpp @@ -131,6 +131,18 @@ TEST(CoapTest, CoapMessageHeader_TokenIsPresent) EXPECT_EQ(message->GetToken(), ByteArray{0xfa}); } +TEST(CoapTest, CoapMessageHeader_TokenLengthIsZero) +{ + ByteArray buffer{'`', 0, 0, 1}; + Error error; + auto message = Message::Deserialize(error, buffer); + + EXPECT_NE(message, nullptr); + EXPECT_EQ(error, ErrorCode::kNone); + + EXPECT_EQ(message->GetToken(), ByteArray{}); +} + TEST(CoapTest, CoapMessageHeader_TokenLengthIsTooLong) { ByteArray buffer{0x49, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}; From e0820a311fbd8d5f929a3dd7bed510a5cfc56fcc Mon Sep 17 00:00:00 2001 From: Kangping Date: Tue, 16 Jul 2024 02:21:52 +0800 Subject: [PATCH 12/13] [swig] fix the SWIG ignores for java (#287) The commissioner.i file is behind the APIs in include/commissioner/. Also ignores `PrintTo` given it's only for googletest. --- src/java/commissioner.i | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/java/commissioner.i b/src/java/commissioner.i index 65f381e3..e6725c85 100644 --- a/src/java/commissioner.i +++ b/src/java/commissioner.i @@ -43,8 +43,8 @@ #include %} -%include %include +%include %include %include %include @@ -63,6 +63,7 @@ %apply signed char { uint8_t }; %apply const signed char & { const uint8_t & }; %template(ByteArray) std::vector; + // Override the typemap of `uint8_t`. %apply unsigned char { uint8_t }; %apply const unsigned char & { const uint8_t & }; @@ -140,7 +141,6 @@ namespace commissioner { %ignore Commissioner::GetPendingDataset(Handler aHandler, uint16_t aDatasetFlags); %ignore Commissioner::SetPendingDataset(ErrorHandler aHandler, const PendingOperationalDataset &aPendingDataset); %ignore Commissioner::SetSecurePendingDataset(ErrorHandler aHandler, - const std::string & aPbbrAddr, uint32_t aMaxRetrievalTimer, const PendingOperationalDataset &aDataset); %ignore Commissioner::CommandReenroll(ErrorHandler aHandler, const std::string &aDstAddr); @@ -164,7 +164,6 @@ namespace commissioner { uint16_t aScanDuration, const std::string &aDstAddr); %ignore Commissioner::RegisterMulticastListener(Handler aHandler, - const std::string & aPbbrAddr, const std::vector &aMulticastAddrList, uint32_t aTimeout); %ignore Commissioner::RequestToken(Handler aHandler, const std::string &aAddr, uint16_t aPort); @@ -179,6 +178,8 @@ namespace commissioner { %ignore operator!=(const Error &aError, const ErrorCode &aErrorCode); %ignore operator==(const ErrorCode &aErrorCode, const Error &aError); %ignore operator!=(const ErrorCode &aErrorCode, const Error &aError); + %ignore PrintTo(const Error &aError, std::ostream *os); + %ignore PrintTo(ErrorCode aErrorCode, std::ostream *os); } } From 70c626d48b78b39b2989ef216f818a6993679955 Mon Sep 17 00:00:00 2001 From: lezhan Date: Mon, 6 May 2024 06:21:05 +0000 Subject: [PATCH 13/13] [tlv] add new tlvs for network diagnostic libotcommissioner.jar, a versatile Java library, provides support for wide range of TMF message transactions, including MeshCop protocols and diagnostic TLVs. This PR focuses on integrating all the diagnostic TLVs, as defined in the spec `10.11.3` into the library's TLV module --- src/library/tlv.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/library/tlv.cpp b/src/library/tlv.cpp index 0dc7603e..2226db4e 100644 --- a/src/library/tlv.cpp +++ b/src/library/tlv.cpp @@ -244,7 +244,7 @@ bool Tlv::IsValid() const case Type::kNetworkDiagIpv6Address: return (length % 16 == 0) && (length / 16 >= 1 && length / 16 <= 15); case Type::kNetworkDiagMacCounters: - return length <= 36; + return length >= 36; case Type::kNetworkDiagBatteryLevel: return length == 1; case Type::kNetworkDiagSupplyVoltage: @@ -266,23 +266,23 @@ bool Tlv::IsValid() const case Type::kNetworkDiagVersion: return length == 2; case Type::kNetworkDiagVendorName: - return length <= 4; + return length >= 4; case Type::kNetworkDiagVendorModel: - return length <= 4; + return length >= 4; case Type::kNetworkDiagVendorSWVersion: - return length <= 2; + return length >= 2; case Type::kNetworkDiagChild: - return length <= 43; + return length >= 43; case Type::kNetworkDiagChildIpv6Address: return (length % 16 == 0) && (length / 16 >= 1 && length / 16 <= 15); case Type::kNetworkDiagRouterNeighbor: - return length <= 24; + return length >= 24; case Type::kNetworkDiagAnswer: return length == 2; case Type::kNetworkDiagQueryID: return length == 2; case Type::kNetworkDiagMleCounters: - return length <= 66; + return length >= 66; default: return false; }