From 382e486c6553ef78ce0bc923bbc85dc500ebd6c2 Mon Sep 17 00:00:00 2001 From: Li Cao Date: Sat, 21 Feb 2026 01:18:10 +0800 Subject: [PATCH] [ncp] implement ncp platform dnssd srv resolve (#12462) This commit implements otPlatDnssdStartSrvResolver and otPlatDnssdStopSrvResolver to support service discovery on NCP. This commit contains these changes: * Add new spinel property for starting / stopping service resolver * Implement encoding/decoding of the new property * Add unit test for encoding/decoding * Implement ncp version of dnssd platform API otPlatDnssdStartSrvResolver and otPlatDnssdStopSrvResolver * Add property handler to get resolver result on NCP side * Add unit test to verify that the resolver callback is correctly invoked after getting resolver result. --- src/lib/spinel/spinel.c | 2 + src/lib/spinel/spinel.h | 34 ++++++ src/lib/spinel/spinel_prop_codec.cpp | 87 ++++++++++++++ src/lib/spinel/spinel_prop_codec.hpp | 38 ++++++ src/ncp/ncp_base.hpp | 19 +++ src/ncp/ncp_base_dispatcher.cpp | 1 + src/ncp/ncp_base_ftd.cpp | 26 ++++ src/ncp/platform/dnssd.cpp | 4 +- tests/unit/test_ncp_dnssd.cpp | 73 ++++++++++++ tests/unit/test_spinel_prop_codec.cpp | 164 ++++++++++++++++++++++++-- 10 files changed, 434 insertions(+), 14 deletions(-) diff --git a/src/lib/spinel/spinel.c b/src/lib/spinel/spinel.c index 39e684617..62340241e 100644 --- a/src/lib/spinel/spinel.c +++ b/src/lib/spinel/spinel.c @@ -1421,6 +1421,8 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) {SPINEL_PROP_DNSSD_KEY_RECORD, "DNSSD_KEY_RECORD"}, {SPINEL_PROP_DNSSD_BROWSER, "DNSSD_BROWSER"}, {SPINEL_PROP_DNSSD_BROWSE_RESULT, "DNSSD_BROWSE_RESULT"}, + {SPINEL_PROP_DNSSD_SRV_RESOLVER, "DNSSD_SRV_RESOLVER"}, + {SPINEL_PROP_DNSSD_SRV_RESULT, "DNSSD_SRV_RESULT"}, {SPINEL_PROP_BORDER_AGENT_MESHCOP_SERVICE_STATE, "BORDER_AGENT_MESHCOP_SERVICE_STATE"}, {SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_STATE, "SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_STATE"}, {SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_ENABLE, "SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_ENABLE"}, diff --git a/src/lib/spinel/spinel.h b/src/lib/spinel/spinel.h index fb42e30df..8a9d5f0c8 100644 --- a/src/lib/spinel/spinel.h +++ b/src/lib/spinel/spinel.h @@ -4925,6 +4925,40 @@ enum */ SPINEL_PROP_DNSSD_BROWSE_RESULT = SPINEL_PROP_DNSSD__BEGIN + 7, + /// DNS-SD Service Resolver + /** + * Format: `UULD`: Inserted/Removed + * + * `U`: The service instance label. + * `U`: The service type. + * `L`: The infrastructure network interface index. + * `D`: The context of the request. A pointer to the callback to receive the result. + * + * NCP uses this property to resolve services. + */ + SPINEL_PROP_DNSSD_SRV_RESOLVER = SPINEL_PROP_DNSSD__BEGIN + 8, + + /** + * DNS-SD SRV Resolution Result + * + * Format: `UUt(U)SSSLLD`: Set + * + * Reports the result of a DNS-SD service resolution on the infrastructure + * network. + * + * Content of the `otPlatDnssdSrvResult` struct: + * `U`: The service instance name label. + * `U`: The service type. + * `U`: The host name (e.g., "myhost"). Can be NULL when `mTtl` is zero. + * `S`: The service port number. + * `S`: The service priority. + * `S`: The service weight. + * `L`: The service TTL in seconds. Zero TTL indicates SRV record is removed. + * `L`: The infrastructure network interface index. + * `D`: The context of the request. A pointer to the callback to receive the result. + */ + SPINEL_PROP_DNSSD_SRV_RESULT = SPINEL_PROP_DNSSD__BEGIN + 9, + SPINEL_PROP_DNSSD__END = 0x950, SPINEL_PROP_BORDER_AGENT__BEGIN = 0x950, diff --git a/src/lib/spinel/spinel_prop_codec.cpp b/src/lib/spinel/spinel_prop_codec.cpp index bc50fb915..9751d3030 100644 --- a/src/lib/spinel/spinel_prop_codec.cpp +++ b/src/lib/spinel/spinel_prop_codec.cpp @@ -290,5 +290,92 @@ exit: return error; } +template <> +otError EncodeDnssdDiscovery(Encoder &aEncoder, const otPlatDnssdSrvResolver &aDiscovery) +{ + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = aEncoder.WriteUtf8(aDiscovery.mServiceInstance)); + SuccessOrExit(error = aEncoder.WriteUtf8(aDiscovery.mServiceType)); + SuccessOrExit(error = aEncoder.WriteUint32(aDiscovery.mInfraIfIndex)); + SuccessOrExit(error = aEncoder.WriteData(reinterpret_cast(&aDiscovery.mCallback), + sizeof(aDiscovery.mCallback))); + +exit: + return error; +} + +otError EncodeDnssdSrvResult(Encoder &aEncoder, + const otPlatDnssdSrvResult &aSrvResult, + const uint8_t *aCallbackData, + uint16_t aCallbackDataLen) +{ + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = aEncoder.WriteUtf8(aSrvResult.mServiceInstance)); + SuccessOrExit(error = aEncoder.WriteUtf8(aSrvResult.mServiceType)); + SuccessOrExit(error = aEncoder.OpenStruct()); + if (aSrvResult.mHostName != nullptr) + { + SuccessOrExit(error = aEncoder.WriteUtf8(aSrvResult.mHostName)); + } + SuccessOrExit(error = aEncoder.CloseStruct()); + SuccessOrExit(error = aEncoder.WriteUint16(aSrvResult.mPort)); + SuccessOrExit(error = aEncoder.WriteUint16(aSrvResult.mPriority)); + SuccessOrExit(error = aEncoder.WriteUint16(aSrvResult.mWeight)); + SuccessOrExit(error = aEncoder.WriteUint32(aSrvResult.mTtl)); + SuccessOrExit(error = aEncoder.WriteUint32(aSrvResult.mInfraIfIndex)); + SuccessOrExit(error = aEncoder.WriteData(aCallbackData, aCallbackDataLen)); + +exit: + return error; +} + +otError DecodeDnssdSrvResolver(Decoder &aDecoder, + otPlatDnssdSrvResolver &aSrvResolver, + const uint8_t *&aCallbackData, + uint16_t &aCallbackDataLen) +{ + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = aDecoder.ReadUtf8(aSrvResolver.mServiceInstance)); + SuccessOrExit(error = aDecoder.ReadUtf8(aSrvResolver.mServiceType)); + SuccessOrExit(error = aDecoder.ReadUint32(aSrvResolver.mInfraIfIndex)); + SuccessOrExit(error = aDecoder.ReadData(aCallbackData, aCallbackDataLen)); + +exit: + return error; +} + +otError DecodeDnssdSrvResult(Decoder &aDecoder, + otPlatDnssdSrvResult &aSrvResult, + const uint8_t *&aCallbackData, + uint16_t &aCallbackDataLen) +{ + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = aDecoder.ReadUtf8(aSrvResult.mServiceInstance)); + SuccessOrExit(error = aDecoder.ReadUtf8(aSrvResult.mServiceType)); + SuccessOrExit(error = aDecoder.OpenStruct()); + if (!aDecoder.IsAllReadInStruct()) + { + SuccessOrExit(error = aDecoder.ReadUtf8(aSrvResult.mHostName)); + } + else + { + aSrvResult.mHostName = nullptr; + } + SuccessOrExit(error = aDecoder.CloseStruct()); + SuccessOrExit(error = aDecoder.ReadUint16(aSrvResult.mPort)); + SuccessOrExit(error = aDecoder.ReadUint16(aSrvResult.mPriority)); + SuccessOrExit(error = aDecoder.ReadUint16(aSrvResult.mWeight)); + SuccessOrExit(error = aDecoder.ReadUint32(aSrvResult.mTtl)); + SuccessOrExit(error = aDecoder.ReadUint32(aSrvResult.mInfraIfIndex)); + SuccessOrExit(error = aDecoder.ReadData(aCallbackData, aCallbackDataLen)); + +exit: + return error; +} + } // namespace Spinel } // namespace ot diff --git a/src/lib/spinel/spinel_prop_codec.hpp b/src/lib/spinel/spinel_prop_codec.hpp index 595f83525..979abd1a8 100644 --- a/src/lib/spinel/spinel_prop_codec.hpp +++ b/src/lib/spinel/spinel_prop_codec.hpp @@ -87,6 +87,19 @@ otError EncodeDnssdBrowseResult(Encoder &aEncoder, const uint8_t *aCallbackData, uint16_t aCallbackDataLen); +/** + * Use Spinel::Encode to encode a Dnssd SRV result. + * + * @param[in] aEncoder A reference to the encoder object. + * @param[in] aSrvResult A reference to the SRV result object. + * @param[in] aCallbackData A pointer to the callback data. + * @param[in] aCallbackDataLen The data length. + */ +otError EncodeDnssdSrvResult(Encoder &aEncoder, + const otPlatDnssdSrvResult &aSrvResult, + const uint8_t *aCallbackData, + uint16_t aCallbackDataLen); + /** * Use Spinel::Decoder to decode a SPINEL_PROP_DNSSD_HOST message to a otPlatDnssdHost. * @@ -172,6 +185,31 @@ otError DecodeDnssdBrowseResult(Decoder &aDecoder, const uint8_t *&aCallbackData, uint16_t &aCallbackDataLen); +/** + * Use Spinel::Decoder to decode a SPINEL_PROP_DNSSD_SRV_RESOLVER message to a otPlatDnssdSrvResolver. + * + * @param[in] aDecoder A reference to the decoder object. + * @param[out] aSrvResolver A reference to the SRV resolver. + * @param[out] aCallbackData A reference to the pointer to the callback data. + * @param[out] aCallbackDataLen A reference to the callback data length. + */ +otError DecodeDnssdSrvResolver(Decoder &aDecoder, + otPlatDnssdSrvResolver &aSrvResolver, + const uint8_t *&aCallbackData, + uint16_t &aCallbackDataLen); + +/** + * Use Spinel::Decoder to decode a Dnssd SRV result. + * + * @param[in] aDecoder A reference to the decoder object. + * @param[out] aSrvResult A reference to the SRV result. + * @param[out] aCallbackData A reference to the pointer to the callback data. + * @param[out] aCallbackDataLen A reference to the callback data length. + */ +otError DecodeDnssdSrvResult(Decoder &aDecoder, + otPlatDnssdSrvResult &aSrvResult, + const uint8_t *&aCallbackData, + uint16_t &aCallbackDataLen); } // namespace Spinel } // namespace ot diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index bd8b04b98..a0f4d3526 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -324,6 +324,20 @@ public: */ void DnssdStopBrowser(const otPlatDnssdBrowser *aBrowser); + /** + * Starts a service resolver. + * + * @param[in] aResolver The resolver to be started. + */ + void DnssdStartSrvResolver(const otPlatDnssdSrvResolver *aResolver); + + /** + * Stops a service resolver. + * + * @param[in] aResolver The resolver to be stopped. + */ + void DnssdStopSrvResolver(const otPlatDnssdSrvResolver *aResolver); + /** * Gets the Dnssd state. * @@ -944,6 +958,11 @@ template <> struct NcpBase::DnssdDiscoveryPropKeyFor { static constexpr spinel_prop_key_t Key = SPINEL_PROP_DNSSD_BROWSER; }; + +template <> struct NcpBase::DnssdDiscoveryPropKeyFor +{ + static constexpr spinel_prop_key_t Key = SPINEL_PROP_DNSSD_SRV_RESOLVER; +}; #endif } // namespace Ncp diff --git a/src/ncp/ncp_base_dispatcher.cpp b/src/ncp/ncp_base_dispatcher.cpp index fffb9af9e..f025e95a6 100644 --- a/src/ncp/ncp_base_dispatcher.cpp +++ b/src/ncp/ncp_base_dispatcher.cpp @@ -546,6 +546,7 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey) OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_DNSSD_STATE), OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_DNSSD_REQUEST_RESULT), OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_DNSSD_BROWSE_RESULT), + OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_DNSSD_SRV_RESULT), #endif #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_ENABLE), diff --git a/src/ncp/ncp_base_ftd.cpp b/src/ncp/ncp_base_ftd.cpp index 33c4706cd..bcc8d54cc 100644 --- a/src/ncp/ncp_base_ftd.cpp +++ b/src/ncp/ncp_base_ftd.cpp @@ -1740,6 +1740,16 @@ void NcpBase::DnssdStopBrowser(const otPlatDnssdBrowser *aBrowser) DnssdUpdateDiscovery(aBrowser, /* aStart */ false); } +void NcpBase::DnssdStartSrvResolver(const otPlatDnssdSrvResolver *aResolver) +{ + DnssdUpdateDiscovery(aResolver, /* aStart */ true); +} + +void NcpBase::DnssdStopSrvResolver(const otPlatDnssdSrvResolver *aResolver) +{ + DnssdUpdateDiscovery(aResolver, /* aStart */ false); +} + otPlatDnssdState NcpBase::DnssdGetState(void) { return mDnssdState; } template <> otError NcpBase::HandlePropertySet(void) @@ -1796,6 +1806,22 @@ exit: return error; } +template <> otError NcpBase::HandlePropertySet(void) +{ + otError error = OT_ERROR_NONE; + otPlatDnssdSrvResult srvResult; + otPlatDnssdSrvCallback callback = nullptr; + const uint8_t *context; + uint16_t contextLen; + + SuccessOrExit(error = DecodeDnssdSrvResult(mDecoder, srvResult, context, contextLen)); + VerifyOrExit(contextLen == sizeof(otPlatDnssdSrvCallback), error = OT_ERROR_PARSE); + callback = *reinterpret_cast(context); + callback(mInstance, &srvResult); + +exit: + return error; +} #endif // OPENTHREAD_CONFIG_NCP_DNSSD_ENABLE && OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE diff --git a/src/ncp/platform/dnssd.cpp b/src/ncp/platform/dnssd.cpp index 8723d9406..9ee5fc5de 100644 --- a/src/ncp/platform/dnssd.cpp +++ b/src/ncp/platform/dnssd.cpp @@ -124,13 +124,13 @@ void otPlatDnssdStopBrowser(otInstance *aInstance, const otPlatDnssdBrowser *aBr void otPlatDnssdStartSrvResolver(otInstance *aInstance, const otPlatDnssdSrvResolver *aResolver) { OT_UNUSED_VARIABLE(aInstance); - OT_UNUSED_VARIABLE(aResolver); + ot::Ncp::NcpBase::GetNcpInstance()->DnssdStartSrvResolver(aResolver); } void otPlatDnssdStopSrvResolver(otInstance *aInstance, const otPlatDnssdSrvResolver *aResolver) { OT_UNUSED_VARIABLE(aInstance); - OT_UNUSED_VARIABLE(aResolver); + ot::Ncp::NcpBase::GetNcpInstance()->DnssdStopSrvResolver(aResolver); } void otPlatDnssdStartTxtResolver(otInstance *aInstance, const otPlatDnssdTxtResolver *aResolver) diff --git a/tests/unit/test_ncp_dnssd.cpp b/tests/unit/test_ncp_dnssd.cpp index 05b892bb0..9e9274deb 100644 --- a/tests/unit/test_ncp_dnssd.cpp +++ b/tests/unit/test_ncp_dnssd.cpp @@ -244,6 +244,78 @@ void TestNcpDnssdBrowse(void) VerifyOrQuit(sDnssdBrowseCallbackInvoked); } +static bool sDnssdSrvCallbackInvoked = false; + +static void TestDnssdSrvCallback(otInstance *aInstance, const otPlatDnssdSrvResult *aResult) +{ + OT_UNUSED_VARIABLE(aInstance); + + VerifyOrQuit(strcmp(aResult->mServiceInstance, "GAT-X303 #1") == 0); + VerifyOrQuit(strcmp(aResult->mServiceType, "_ms._tcp") == 0); + VerifyOrQuit(strcmp(aResult->mHostName, "GAT-X303 #1._ms._tcp.local") == 0); + VerifyOrQuit(aResult->mPort == 5353); + VerifyOrQuit(aResult->mPriority == 1); + VerifyOrQuit(aResult->mWeight == 10); + VerifyOrQuit(aResult->mTtl == 120); + VerifyOrQuit(aResult->mInfraIfIndex == 1); + + sDnssdSrvCallbackInvoked = true; +} + +static otError GenerateSpinelDnssdSrvResultFrame(const otPlatDnssdSrvResult &aSrvResult, uint8_t *aBuf, uint16_t &aLen) +{ + otError error = OT_ERROR_NONE; + uint8_t buf[kMaxSpinelBufferSize]; + Spinel::Buffer ncpBuffer(buf, kMaxSpinelBufferSize); + Spinel::Encoder encoder(ncpBuffer); + otPlatDnssdSrvCallback callback = &TestDnssdSrvCallback; + + uint8_t header = SPINEL_HEADER_FLAG | 0 /* Iid */ | 1 /* Tid */; + SuccessOrExit(error = encoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_DNSSD_SRV_RESULT)); + SuccessOrExit(error = EncodeDnssdSrvResult(encoder, aSrvResult, reinterpret_cast(&callback), + sizeof(callback))); + SuccessOrExit(error = encoder.EndFrame()); + + SuccessOrExit(ncpBuffer.OutFrameBegin()); + aLen = ncpBuffer.OutFrameGetLength(); + VerifyOrExit(ncpBuffer.OutFrameRead(aLen, aBuf) == aLen, error = OT_ERROR_FAILED); + +exit: + return error; +} + +void TestNcpDnssdSrvResolve(void) +{ + Instance *instance = static_cast(testInitInstance()); + Ncp::NcpBase ncpBase(instance); + uint8_t recvBuf[kMaxSpinelBufferSize]; + uint16_t recvLen; + otPlatDnssdSrvResolver resolver; + otPlatDnssdSrvResult srvResult; + + resolver.mServiceInstance = "GAT-X303 #1"; + resolver.mServiceType = "_ms._tcp"; + resolver.mInfraIfIndex = 1; + resolver.mCallback = TestDnssdSrvCallback; + + otPlatDnssdStartSrvResolver(instance, &resolver); + + srvResult.mServiceInstance = "GAT-X303 #1"; + srvResult.mServiceType = "_ms._tcp"; + srvResult.mHostName = "GAT-X303 #1._ms._tcp.local"; + srvResult.mPort = 5353; + srvResult.mPriority = 1; + srvResult.mWeight = 10; + srvResult.mTtl = 120; + srvResult.mInfraIfIndex = 1; + + SuccessOrQuit(GenerateSpinelDnssdSrvResultFrame(srvResult, recvBuf, recvLen)); + + ncpBase.HandleReceive(recvBuf, recvLen); + + VerifyOrQuit(sDnssdSrvCallbackInvoked); +} + } // namespace ot #endif // OPENTHREAD_CONFIG_NCP_DNSSD_ENABLE && OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE @@ -254,6 +326,7 @@ int main(void) ot::TestNcpDnssdGetState(); ot::TestNcpDnssdRegistrations(); ot::TestNcpDnssdBrowse(); + ot::TestNcpDnssdSrvResolve(); #endif printf("All tests passed\n"); return 0; diff --git a/tests/unit/test_spinel_prop_codec.cpp b/tests/unit/test_spinel_prop_codec.cpp index c4c64aa25..458d3e75f 100644 --- a/tests/unit/test_spinel_prop_codec.cpp +++ b/tests/unit/test_spinel_prop_codec.cpp @@ -47,18 +47,25 @@ static void FakeDnssdBrowseCallback(otInstance *aInstance, const otPlatDnssdBrow OT_UNUSED_VARIABLE(aResult); } +static void FakeDnssdSrvCallback(otInstance *aInstance, const otPlatDnssdSrvResult *aResult) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aResult); +} + +static constexpr uint16_t kMaxSpinelBufferSize = 2048; + void TestDnssd(void) { - constexpr uint16_t kMaxSpinelBufferSize = 2048; - uint8_t buf[kMaxSpinelBufferSize]; - uint16_t len; - Spinel::Buffer ncpBuffer(buf, kMaxSpinelBufferSize); - Spinel::Encoder encoder(ncpBuffer); - Spinel::Decoder decoder; - uint8_t header; - unsigned int command; - unsigned int propKey; - otError error = OT_ERROR_NONE; + uint8_t buf[kMaxSpinelBufferSize]; + uint16_t len; + Spinel::Buffer ncpBuffer(buf, kMaxSpinelBufferSize); + Spinel::Encoder encoder(ncpBuffer); + Spinel::Decoder decoder; + uint8_t header; + unsigned int command; + unsigned int propKey; + otError error = OT_ERROR_NONE; // Test DnssdHost encoding and decoding otPlatDnssdHost dnssdHostEncode; @@ -184,8 +191,22 @@ void TestDnssd(void) VerifyOrQuit(requestId == 3); VerifyOrQuit(callbackDataLen == sizeof(otPlatDnssdRegisterCallback)); VerifyOrQuit(*reinterpret_cast(callbackData) == DnssdFakeCallback); +} + +void TestDnssdBrowser(void) +{ + uint8_t buf[kMaxSpinelBufferSize]; + Spinel::Buffer ncpBuffer(buf, kMaxSpinelBufferSize); + uint16_t len; + Spinel::Encoder encoder(ncpBuffer); + Spinel::Decoder decoder; + uint8_t header; + unsigned int command; + unsigned int propKey; + const uint8_t *callbackData; + uint16_t callbackDataLen; + otError error = OT_ERROR_NONE; - // Test Dnssd Browser encoding and decoding otPlatDnssdBrowser dnssdBrowserEncode; otPlatDnssdBrowser dnssdBrowserDecode; @@ -216,8 +237,22 @@ void TestDnssd(void) VerifyOrQuit(dnssdBrowserDecode.mInfraIfIndex == dnssdBrowserEncode.mInfraIfIndex); VerifyOrQuit(callbackDataLen == sizeof(otPlatDnssdBrowseCallback)); VerifyOrQuit(*reinterpret_cast(callbackData) == FakeDnssdBrowseCallback); +} + +void TestDnssdBrowserResult(void) +{ + uint8_t buf[kMaxSpinelBufferSize]; + Spinel::Buffer ncpBuffer(buf, kMaxSpinelBufferSize); + uint16_t len; + Spinel::Encoder encoder(ncpBuffer); + Spinel::Decoder decoder; + uint8_t header; + unsigned int command; + unsigned int propKey; + const uint8_t *callbackData; + uint16_t callbackDataLen; + otError error = OT_ERROR_NONE; - // Test Dnssd Browser Result encoding and decoding otPlatDnssdBrowseResult dnssdBrowseResultEncode; otPlatDnssdBrowseResult dnssdBrowseResultDecode; @@ -255,12 +290,117 @@ void TestDnssd(void) VerifyOrQuit(*reinterpret_cast(callbackData) == FakeDnssdBrowseCallback); } +void TestDnssdSrvResolver(void) +{ + constexpr uint16_t kMaxSpinelBufferSize = 2048; + uint8_t buf[kMaxSpinelBufferSize]; + uint16_t len; + Spinel::Buffer ncpBuffer(buf, kMaxSpinelBufferSize); + Spinel::Encoder encoder(ncpBuffer); + Spinel::Decoder decoder; + uint8_t header; + unsigned int command; + unsigned int propKey; + + otError error = OT_ERROR_NONE; + + otPlatDnssdSrvResolver srvResolverEncode; + otPlatDnssdSrvResolver srvResolverDecode; + const uint8_t *callbackData; + uint16_t callbackDataLen; + + srvResolverEncode.mServiceInstance = "ZGMF-X10A #1"; + srvResolverEncode.mServiceType = "_ms._tcp"; + srvResolverEncode.mInfraIfIndex = 1; + srvResolverEncode.mCallback = FakeDnssdSrvCallback; + + ncpBuffer.Clear(); + SuccessOrQuit( + error = encoder.BeginFrame(SPINEL_HEADER_FLAG, SPINEL_CMD_PROP_VALUE_INSERTED, SPINEL_PROP_DNSSD_SRV_RESOLVER)); + SuccessOrQuit(error = EncodeDnssdDiscovery(encoder, srvResolverEncode)); + SuccessOrQuit(error = encoder.EndFrame()); + SuccessOrQuit(ncpBuffer.OutFrameBegin()); + len = ncpBuffer.OutFrameGetLength(); + VerifyOrQuit(ncpBuffer.OutFrameRead(len, buf) == len); + + decoder.Init(buf, len); + SuccessOrQuit(error = decoder.ReadUint8(header)); + SuccessOrQuit(error = decoder.ReadUintPacked(command)); + SuccessOrQuit(error = decoder.ReadUintPacked(propKey)); + SuccessOrQuit(error = DecodeDnssdSrvResolver(decoder, srvResolverDecode, callbackData, callbackDataLen)); + VerifyOrQuit(strcmp(srvResolverDecode.mServiceInstance, srvResolverEncode.mServiceInstance) == 0); + VerifyOrQuit(strcmp(srvResolverDecode.mServiceType, srvResolverEncode.mServiceType) == 0); + VerifyOrQuit(srvResolverDecode.mInfraIfIndex == srvResolverEncode.mInfraIfIndex); + VerifyOrQuit(callbackDataLen == sizeof(otPlatDnssdSrvCallback)); + VerifyOrQuit(*reinterpret_cast(callbackData) == FakeDnssdSrvCallback); +} + +void TestDnssdSrvResult(void) +{ + constexpr uint16_t kMaxSpinelBufferSize = 2048; + uint8_t buf[kMaxSpinelBufferSize]; + uint16_t len; + Spinel::Buffer ncpBuffer(buf, kMaxSpinelBufferSize); + Spinel::Encoder encoder(ncpBuffer); + Spinel::Decoder decoder; + uint8_t header; + unsigned int command; + unsigned int propKey; + otError error = OT_ERROR_NONE; + + otPlatDnssdSrvResult srvResultEncode; + otPlatDnssdSrvResult srvResultDecode; + const uint8_t *callbackData; + uint16_t callbackDataLen; + + srvResultEncode.mServiceInstance = "ZGMF-X13A #1"; + srvResultEncode.mServiceType = "_ms._tcp"; + srvResultEncode.mHostName = "ZGMF-X13A #1._ms._tcp.local."; + srvResultEncode.mPort = 5353; + srvResultEncode.mPriority = 10; + srvResultEncode.mWeight = 100; + srvResultEncode.mTtl = 120; + srvResultEncode.mInfraIfIndex = 1; + + otPlatDnssdSrvCallback callback = FakeDnssdSrvCallback; + + ncpBuffer.Clear(); + SuccessOrQuit(error = + encoder.BeginFrame(SPINEL_HEADER_FLAG, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_DNSSD_SRV_RESULT)); + SuccessOrQuit(error = EncodeDnssdSrvResult(encoder, srvResultEncode, reinterpret_cast(&callback), + sizeof(callback))); + SuccessOrQuit(error = encoder.EndFrame()); + SuccessOrQuit(ncpBuffer.OutFrameBegin()); + len = ncpBuffer.OutFrameGetLength(); + VerifyOrQuit(ncpBuffer.OutFrameRead(len, buf) == len); + + decoder.Init(buf, len); + SuccessOrQuit(error = decoder.ReadUint8(header)); + SuccessOrQuit(error = decoder.ReadUintPacked(command)); + SuccessOrQuit(error = decoder.ReadUintPacked(propKey)); + SuccessOrQuit(error = DecodeDnssdSrvResult(decoder, srvResultDecode, callbackData, callbackDataLen)); + VerifyOrQuit(strcmp(srvResultDecode.mServiceInstance, srvResultEncode.mServiceInstance) == 0); + VerifyOrQuit(strcmp(srvResultDecode.mServiceType, srvResultEncode.mServiceType) == 0); + VerifyOrQuit(strcmp(srvResultDecode.mHostName, srvResultEncode.mHostName) == 0); + VerifyOrQuit(srvResultDecode.mPort == srvResultEncode.mPort); + VerifyOrQuit(srvResultDecode.mPriority == srvResultEncode.mPriority); + VerifyOrQuit(srvResultDecode.mWeight == srvResultEncode.mWeight); + VerifyOrQuit(srvResultDecode.mTtl == srvResultEncode.mTtl); + VerifyOrQuit(srvResultDecode.mInfraIfIndex == srvResultEncode.mInfraIfIndex); + VerifyOrQuit(callbackDataLen == sizeof(otPlatDnssdSrvCallback)); + VerifyOrQuit(*reinterpret_cast(callbackData) == FakeDnssdSrvCallback); +} + } // namespace Spinel } // namespace ot int main(void) { ot::Spinel::TestDnssd(); + ot::Spinel::TestDnssdBrowser(); + ot::Spinel::TestDnssdBrowserResult(); + ot::Spinel::TestDnssdSrvResolver(); + ot::Spinel::TestDnssdSrvResult(); printf("\nAll tests passed.\n"); return 0; }