Skip to content

Commit

Permalink
Platform impl for commissionable node discovery (#7633)
Browse files Browse the repository at this point in the history
* Platform impl for commissionable node discovery

* Address review comments from Damian
  • Loading branch information
cecille authored Jun 16, 2021
1 parent 33ee77a commit 2fbc3fd
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 7 deletions.
3 changes: 3 additions & 0 deletions src/inet/tests/TestInetLayerDNS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ static void TestDNSResolution_NoRecord(nlTestSuite * testSuite, void * testConte
static void TestDNSResolution_NoHostRecord(nlTestSuite * testSuite, void * testContext)
{
// clang-format off
#ifndef DISABLE_BROKEN_DNS_TESTS

// Test resolving a name that has no host records (A or AAAA).
RunTestCase(testSuite,
Expand Down Expand Up @@ -339,6 +340,8 @@ static void TestDNSResolution_NoHostRecord(nlTestSuite * testSuite, void * testC
false
}
);
#endif

// clang-format on
}

Expand Down
45 changes: 45 additions & 0 deletions src/lib/mdns/Discovery_ImplPlatform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@

#include "ServiceNaming.h"
#include "lib/core/CHIPSafeCasts.h"
#include "lib/mdns/TxtFields.h"
#include "lib/mdns/platform/Mdns.h"
#include "lib/support/logging/CHIPLogging.h"
#include "platform/CHIPDeviceConfig.h"
#include "platform/CHIPDeviceLayer.h"
#include "setup_payload/AdditionalDataPayloadGenerator.h"
#include "support/CHIPMemString.h"
#include "support/CodeUtils.h"
#include "support/ErrorStr.h"
#include "support/RandUtils.h"
Expand Down Expand Up @@ -431,6 +433,49 @@ CHIP_ERROR DiscoveryImplPlatform::ResolveNodeId(const PeerId & peerId, Inet::IPA
return ChipMdnsResolve(&service, INET_NULL_INTERFACEID, HandleNodeIdResolve, this);
}

void DiscoveryImplPlatform::HandleCommissionableNodeBrowse(void * context, MdnsService * services, size_t servicesSize,
CHIP_ERROR error)
{
for (size_t i = 0; i < servicesSize; ++i)
{
ChipMdnsResolve(&services[i], INET_NULL_INTERFACEID, HandleCommissionableNodeResolve, context);
}
}

void DiscoveryImplPlatform::HandleCommissionableNodeResolve(void * context, MdnsService * result, CHIP_ERROR error)
{
if (error != CHIP_NO_ERROR)
{
return;
}
DiscoveryImplPlatform * mgr = static_cast<DiscoveryImplPlatform *>(context);
CommissionableNodeData data;
Platform::CopyString(data.hostName, result->mHostName);

if (result->mAddress.HasValue())
{
data.ipAddress[data.numIPs++] = result->mAddress.Value();
}

for (size_t i = 0; i < result->mTextEntrySize; ++i)
{
ByteSpan key(reinterpret_cast<const uint8_t *>(result->mTextEntries[i].mKey), strlen(result->mTextEntries[i].mKey));
ByteSpan val(result->mTextEntries[i].mData, result->mTextEntries[i].mDataSize);
FillNodeDataFromTxt(key, val, &data);
}
mgr->mResolverDelegate->OnCommissionableNodeFound(data);
}

CHIP_ERROR DiscoveryImplPlatform::FindCommissionableNodes(DiscoveryFilter filter)
{
ReturnErrorOnFailure(Init());
char serviceName[kMaxCommisisonableServiceNameSize];
ReturnErrorOnFailure(MakeCommissionableNodeServiceTypeName(serviceName, sizeof(serviceName), filter));

return ChipMdnsBrowse(serviceName, MdnsServiceProtocol::kMdnsProtocolUdp, Inet::kIPAddressType_Any, INET_NULL_INTERFACEID,
HandleCommissionableNodeBrowse, this);
}

void DiscoveryImplPlatform::HandleNodeIdResolve(void * context, MdnsService * result, CHIP_ERROR error)
{
DiscoveryImplPlatform * mgr = static_cast<DiscoveryImplPlatform *>(context);
Expand Down
4 changes: 3 additions & 1 deletion src/lib/mdns/Discovery_ImplPlatform.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class DiscoveryImplPlatform : public ServiceAdvertiser, public Resolver
/// Requests resolution of a node ID to its address
CHIP_ERROR ResolveNodeId(const PeerId & peerId, Inet::IPAddressType type) override;

CHIP_ERROR FindCommissionableNodes(DiscoveryFilter filter = DiscoveryFilter()) override { return CHIP_ERROR_NOT_IMPLEMENTED; }
CHIP_ERROR FindCommissionableNodes(DiscoveryFilter filter = DiscoveryFilter()) override;

static DiscoveryImplPlatform & GetInstance();

Expand All @@ -70,6 +70,8 @@ class DiscoveryImplPlatform : public ServiceAdvertiser, public Resolver
static void HandleNodeIdResolve(void * context, MdnsService * result, CHIP_ERROR error);
static void HandleMdnsInit(void * context, CHIP_ERROR initError);
static void HandleMdnsError(void * context, CHIP_ERROR initError);
static void HandleCommissionableNodeBrowse(void * context, MdnsService * services, size_t servicesSize, CHIP_ERROR error);
static void HandleCommissionableNodeResolve(void * context, MdnsService * result, CHIP_ERROR error);
static CHIP_ERROR GenerateRotatingDeviceId(char rotatingDeviceIdHexBuffer[], size_t & rotatingDeviceIdHexBufferSize);
#ifdef DETAIL_LOGGING
static void PrintEntries(const MdnsService * service);
Expand Down
19 changes: 19 additions & 0 deletions src/lib/mdns/ServiceNaming.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <cstdio>
#include <inttypes.h>
#include <string.h>

namespace chip {
namespace Mdns {
Expand Down Expand Up @@ -172,5 +173,23 @@ CHIP_ERROR MakeServiceSubtype(char * buffer, size_t bufferLen, DiscoveryFilter s
return (requiredSize <= (bufferLen - 1)) ? CHIP_NO_ERROR : CHIP_ERROR_NO_MEMORY;
}

CHIP_ERROR MakeCommissionableNodeServiceTypeName(char * buffer, size_t bufferLen, DiscoveryFilter nameDesc)
{
size_t requiredSize;
if (nameDesc.type == DiscoveryFilterType::kNone)
{
requiredSize = snprintf(buffer, bufferLen, "_chipc");
}
else
{
ReturnErrorOnFailure(MakeServiceSubtype(buffer, bufferLen, nameDesc));
size_t subtypeLen = strlen(buffer);
requiredSize =
snprintf(buffer + subtypeLen, bufferLen - subtypeLen, ".%s.%s", kSubtypeServiceNamePart, kCommissionableServiceName);
}

return (requiredSize <= (bufferLen - 1)) ? CHIP_NO_ERROR : CHIP_ERROR_NO_MEMORY;
}

} // namespace Mdns
} // namespace chip
2 changes: 2 additions & 0 deletions src/lib/mdns/ServiceNaming.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,7 @@ CHIP_ERROR MakeHostName(char * buffer, size_t bufferLen, const chip::ByteSpan &

CHIP_ERROR MakeServiceSubtype(char * buffer, size_t bufferLen, DiscoveryFilter subtype);

CHIP_ERROR MakeCommissionableNodeServiceTypeName(char * buffer, size_t bufferLen, DiscoveryFilter nameDesc);

} // namespace Mdns
} // namespace chip
97 changes: 93 additions & 4 deletions src/lib/mdns/tests/TestServiceNaming.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,100 @@ void TestMakeServiceNameSubtype(nlTestSuite * inSuite, void * inContext)
NL_TEST_ASSERT(inSuite, strcmp(buffer, "") == 0);
}

void TestMakeCommissionableNodeServiceTypeName(nlTestSuite * inSuite, void * inContext)
{
// TODO(cecille): These need to be changed to remove leading zeros
constexpr size_t kSize = 128;
char buffer[kSize];
DiscoveryFilter filter;

// Long tests
filter.type = DiscoveryFilterType::kLong;
filter.code = 3;
NL_TEST_ASSERT(inSuite, MakeCommissionableNodeServiceTypeName(buffer, sizeof(buffer), filter) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, strcmp(buffer, "_L0003._sub._chipc") == 0);

filter.code = (1 << 12) - 1;
NL_TEST_ASSERT(inSuite, MakeCommissionableNodeServiceTypeName(buffer, sizeof(buffer), filter) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, strcmp(buffer, "_L4095._sub._chipc") == 0);

filter.code = 1 << 12;
NL_TEST_ASSERT(inSuite, MakeCommissionableNodeServiceTypeName(buffer, sizeof(buffer), filter) != CHIP_NO_ERROR);

// Short tests
filter.type = DiscoveryFilterType::kShort;
filter.code = 3;
NL_TEST_ASSERT(inSuite, MakeCommissionableNodeServiceTypeName(buffer, sizeof(buffer), filter) == CHIP_NO_ERROR);
printf("buffer: %s\n", buffer);
NL_TEST_ASSERT(inSuite, strcmp(buffer, "_S003._sub._chipc") == 0);

filter.code = (1 << 8) - 1;
NL_TEST_ASSERT(inSuite, MakeCommissionableNodeServiceTypeName(buffer, sizeof(buffer), filter) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, strcmp(buffer, "_S255._sub._chipc") == 0);

filter.code = 1 << 8;
NL_TEST_ASSERT(inSuite, MakeCommissionableNodeServiceTypeName(buffer, sizeof(buffer), filter) != CHIP_NO_ERROR);

// Vendor tests
filter.type = DiscoveryFilterType::kVendor;
filter.code = 3;
NL_TEST_ASSERT(inSuite, MakeCommissionableNodeServiceTypeName(buffer, sizeof(buffer), filter) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, strcmp(buffer, "_V003._sub._chipc") == 0);
// TODO:add tests for longer vendor codes once the leading zero issue is fixed.

// Device Type tests
filter.type = DiscoveryFilterType::kDeviceType;
filter.code = 3;
NL_TEST_ASSERT(inSuite, MakeCommissionableNodeServiceTypeName(buffer, sizeof(buffer), filter) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, strcmp(buffer, "_T003._sub._chipc") == 0);
// TODO: Add tests for longer device types once the leadng zero issue is fixed.

// Commisioning mode tests
filter.type = DiscoveryFilterType::kCommissioningMode;
filter.code = 0;
NL_TEST_ASSERT(inSuite, MakeCommissionableNodeServiceTypeName(buffer, sizeof(buffer), filter) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, strcmp(buffer, "_C0._sub._chipc") == 0);
filter.code = 1;
NL_TEST_ASSERT(inSuite, MakeCommissionableNodeServiceTypeName(buffer, sizeof(buffer), filter) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, strcmp(buffer, "_C1._sub._chipc") == 0);
filter.code = 2; // only or or 1 allwoed
NL_TEST_ASSERT(inSuite, MakeCommissionableNodeServiceTypeName(buffer, sizeof(buffer), filter) != CHIP_NO_ERROR);

// Commissioning mode open from command
filter.type = DiscoveryFilterType::kCommissioningModeFromCommand;
filter.code = 1;
NL_TEST_ASSERT(inSuite, MakeCommissionableNodeServiceTypeName(buffer, sizeof(buffer), filter) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, strcmp(buffer, "_A1._sub._chipc") == 0);
filter.code = 0; // 1 is only value allowed
NL_TEST_ASSERT(inSuite, MakeCommissionableNodeServiceTypeName(buffer, sizeof(buffer), filter) != CHIP_NO_ERROR);

// None tests.
filter.type = DiscoveryFilterType::kNone;
NL_TEST_ASSERT(inSuite, MakeCommissionableNodeServiceTypeName(buffer, sizeof(buffer), filter) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, strcmp(buffer, "_chipc") == 0);

// Test buffer exactly the right size - "_chipc" = 6 + nullptr = 7
filter.type = DiscoveryFilterType::kNone;
NL_TEST_ASSERT(inSuite, MakeCommissionableNodeServiceTypeName(buffer, 6, filter) == CHIP_ERROR_NO_MEMORY);

// Test buffer exactly the right size - "_chipc" = 6 + nullptr = 7
filter.type = DiscoveryFilterType::kNone;
NL_TEST_ASSERT(inSuite, MakeCommissionableNodeServiceTypeName(buffer, 7, filter) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, strcmp(buffer, "_chipc") == 0);

// Test buffer exactly the right size for subtype - "_C1._sub._chipc" = 15 + nullptr = 16
filter.type = DiscoveryFilterType::kCommissioningMode;
filter.code = 1;
NL_TEST_ASSERT(inSuite, MakeCommissionableNodeServiceTypeName(buffer, 16, filter) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, strcmp(buffer, "_C1._sub._chipc") == 0);
}

const nlTest sTests[] = {
NL_TEST_DEF("MakeInstanceName", TestMakeInstanceName), //
NL_TEST_DEF("ExtractIdFromInstandceName", TestExtractIdFromInstanceName), //
NL_TEST_DEF("TestMakeServiceNameSubtype", TestMakeServiceNameSubtype), //
NL_TEST_SENTINEL() //
NL_TEST_DEF("MakeInstanceName", TestMakeInstanceName), //
NL_TEST_DEF("ExtractIdFromInstandceName", TestExtractIdFromInstanceName), //
NL_TEST_DEF("TestMakeServiceNameSubtype", TestMakeServiceNameSubtype), //
NL_TEST_DEF("TestMakeCommisisonableNodeServiceTypeName", TestMakeCommissionableNodeServiceTypeName), //
NL_TEST_SENTINEL() //
};

} // namespace
Expand Down
4 changes: 3 additions & 1 deletion src/platform/Darwin/MdnsImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include <platform/CHIPDeviceLayer.h>
#include <support/CHIPMem.h>
#include <support/CHIPMemString.h>
#include <support/CodeUtils.h>
#include <support/SafeInt.h>
#include <support/logging/CHIPLogging.h>
Expand Down Expand Up @@ -386,7 +387,8 @@ static void OnGetAddrInfo(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t i
service.mTextEntries = sdCtx->textEntries.empty() ? nullptr : sdCtx->textEntries.data();
service.mTextEntrySize = sdCtx->textEntries.empty() ? 0 : sdCtx->textEntries.size();
service.mAddress.SetValue(chip::Inet::IPAddress::FromSockAddr(*address));
strncpy(service.mName, sdCtx->name, sizeof(service.mName));
Platform::CopyString(service.mName, sdCtx->name);
Platform::CopyString(service.mHostName, hostname);
service.mInterface = sdCtx->interfaceId;

sdCtx->callback(sdCtx->context, &service, CHIP_NO_ERROR);
Expand Down
9 changes: 8 additions & 1 deletion src/platform/Linux/MdnsImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,7 @@ CHIP_ERROR MdnsAvahi::Resolve(const char * name, const char * type, MdnsServiceP

void MdnsAvahi::HandleResolve(AvahiServiceResolver * resolver, AvahiIfIndex interface, AvahiProtocol protocol,
AvahiResolverEvent event, const char * name, const char * type, const char * /*domain*/,
const char * /*host_name*/, const AvahiAddress * address, uint16_t port, AvahiStringList * txt,
const char * host_name, const AvahiAddress * address, uint16_t port, AvahiStringList * txt,
AvahiLookupResultFlags flags, void * userdata)
{
ResolveContext * context = reinterpret_cast<ResolveContext *>(userdata);
Expand All @@ -684,6 +684,13 @@ void MdnsAvahi::HandleResolve(AvahiServiceResolver * resolver, AvahiIfIndex inte
result.mProtocol = GetProtocolInType(type);
result.mPort = port;
result.mAddressType = ToAddressType(protocol);
Platform::CopyString(result.mHostName, host_name);
// Returned value is full QName, want only host part.
char * dot = strchr(result.mHostName, '.');
if (dot != nullptr)
{
*dot = '\0';
}

if (address)
{
Expand Down

0 comments on commit 2fbc3fd

Please sign in to comment.