blob: 8280575aa49cf28210bdc29e98f4d3b1e4a84335 [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <lib/dnssd/Discovery_ImplPlatform.h>
#include <inttypes.h>
#include <crypto/RandUtils.h>
#include <lib/core/CHIPConfig.h>
#include <lib/core/CHIPSafeCasts.h>
#include <lib/dnssd/DnssdCache.h>
#include <lib/dnssd/ServiceNaming.h>
#include <lib/dnssd/TxtFields.h>
#include <lib/dnssd/platform/Dnssd.h>
#include <lib/support/CHIPMemString.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/ErrorStr.h>
#include <lib/support/logging/CHIPLogging.h>
#include <platform/CHIPDeviceConfig.h>
#include <platform/CHIPDeviceLayer.h>
namespace chip {
namespace Dnssd {
DiscoveryImplPlatform DiscoveryImplPlatform::sManager;
#if CHIP_CONFIG_MDNS_CACHE_SIZE > 0
DnssdCache<CHIP_CONFIG_MDNS_CACHE_SIZE> DiscoveryImplPlatform::sDnssdCache;
#endif
DiscoveryImplPlatform::DiscoveryImplPlatform() = default;
CHIP_ERROR DiscoveryImplPlatform::InitImpl()
{
ReturnErrorCodeIf(mDnssdInitialized, CHIP_NO_ERROR);
ReturnErrorOnFailure(ChipDnssdInit(HandleDnssdInit, HandleDnssdError, this));
uint64_t random_instance_name = chip::Crypto::GetRandU64();
memcpy(&mCommissionableInstanceName[0], &random_instance_name, sizeof(mCommissionableInstanceName));
return CHIP_NO_ERROR;
}
void DiscoveryImplPlatform::Shutdown()
{
VerifyOrReturn(mDnssdInitialized);
ChipDnssdShutdown();
}
void DiscoveryImplPlatform::HandleDnssdInit(void * context, CHIP_ERROR initError)
{
DiscoveryImplPlatform * publisher = static_cast<DiscoveryImplPlatform *>(context);
if (initError == CHIP_NO_ERROR)
{
publisher->mDnssdInitialized = true;
#if !CHIP_DEVICE_LAYER_NONE
// Post an event that will start advertising
chip::DeviceLayer::ChipDeviceEvent event;
event.Type = chip::DeviceLayer::DeviceEventType::kDnssdPlatformInitialized;
CHIP_ERROR error = chip::DeviceLayer::PlatformMgr().PostEvent(&event);
if (error != CHIP_NO_ERROR)
{
ChipLogError(Discovery, "Posting DNS-SD platform initialized event failed with %s", chip::ErrorStr(error));
}
#endif
}
else
{
ChipLogError(Discovery, "DNS-SD initialization failed with %s", chip::ErrorStr(initError));
publisher->mDnssdInitialized = false;
}
}
void DiscoveryImplPlatform::HandleDnssdError(void * context, CHIP_ERROR error)
{
DiscoveryImplPlatform * publisher = static_cast<DiscoveryImplPlatform *>(context);
if (error == CHIP_ERROR_FORCED_RESET)
{
if (publisher->mIsOperationalPublishing)
{
publisher->Advertise(publisher->mOperationalAdvertisingParams);
}
if (publisher->mIsCommissionableNodePublishing)
{
publisher->Advertise(publisher->mCommissionableNodeAdvertisingParams);
}
if (publisher->mIsCommissionerPublishing)
{
publisher->Advertise(publisher->mCommissionerAdvertisingParams);
}
publisher->FinalizeServiceUpdate();
}
else
{
ChipLogError(Discovery, "DNS-SD error: %s", chip::ErrorStr(error));
}
}
CHIP_ERROR DiscoveryImplPlatform::GetCommissionableInstanceName(char * instanceName, size_t maxLength)
{
if (maxLength < (chip::Dnssd::Commissionable::kInstanceNameMaxLength + 1))
{
return CHIP_ERROR_NO_MEMORY;
}
return chip::Encoding::BytesToUppercaseHexString(&mCommissionableInstanceName[0], sizeof(mCommissionableInstanceName),
instanceName, maxLength);
}
template <class Derived, size_t N_idle, size_t N_active, size_t N_tcp>
CHIP_ERROR AddCommonTxtElements(const BaseAdvertisingParams<Derived> & params, char (&mrpRetryIdleStorage)[N_idle],
char (&mrpRetryActiveStorage)[N_active], char (&tcpSupportedStorage)[N_tcp],
TextEntry txtEntryStorage[], size_t & txtEntryIdx)
{
Optional<uint32_t> mrpRetryIntervalIdle, mrpRetryIntervalActive;
params.GetMRPRetryIntervals(mrpRetryIntervalIdle, mrpRetryIntervalActive);
// TODO: Issue #5833 - MRP retry intervals should be updated on the poll period value
// change or device type change.
// TODO: Is this really the best place to set these? Seems like it should be passed
// in with the correct values and set one level up from here.
#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
if (chip::DeviceLayer::ConnectivityMgr().GetThreadDeviceType() ==
chip::DeviceLayer::ConnectivityManager::kThreadDeviceType_SleepyEndDevice)
{
uint32_t sedPollPeriod;
ReturnErrorOnFailure(chip::DeviceLayer::ThreadStackMgr().GetPollPeriod(sedPollPeriod));
// Increment default MRP retry intervals by SED poll period to be on the safe side
// and avoid unnecessary retransmissions.
if (mrpRetryIntervalIdle.HasValue())
{
mrpRetryIntervalIdle.SetValue(mrpRetryIntervalIdle.Value() + sedPollPeriod);
}
if (mrpRetryIntervalActive.HasValue())
{
mrpRetryIntervalActive.SetValue(mrpRetryIntervalActive.Value() + sedPollPeriod);
}
}
#endif
if (mrpRetryIntervalIdle.HasValue())
{
if (mrpRetryIntervalIdle.Value() > kMaxRetryInterval)
{
ChipLogProgress(Discovery, "MRP retry interval idle value exceeds allowed range of 1 hour, using maximum available");
mrpRetryIntervalIdle.SetValue(kMaxRetryInterval);
}
size_t writtenCharactersNumber =
snprintf(mrpRetryIdleStorage, sizeof(mrpRetryIdleStorage), "%" PRIu32, mrpRetryIntervalIdle.Value());
VerifyOrReturnError((writtenCharactersNumber > 0) && (writtenCharactersNumber <= kTxtRetryIntervalIdleMaxLength),
CHIP_ERROR_INVALID_STRING_LENGTH);
txtEntryStorage[txtEntryIdx++] = { "CRI", Uint8::from_const_char(mrpRetryIdleStorage), strlen(mrpRetryIdleStorage) };
}
if (mrpRetryIntervalActive.HasValue())
{
if (mrpRetryIntervalActive.Value() > kMaxRetryInterval)
{
ChipLogProgress(Discovery, "MRP retry interval active value exceeds allowed range of 1 hour, using maximum available");
mrpRetryIntervalActive.SetValue(kMaxRetryInterval);
}
size_t writtenCharactersNumber =
snprintf(mrpRetryActiveStorage, sizeof(mrpRetryActiveStorage), "%" PRIu32, mrpRetryIntervalActive.Value());
VerifyOrReturnError((writtenCharactersNumber > 0) && (writtenCharactersNumber <= kTxtRetryIntervalActiveMaxLength),
CHIP_ERROR_INVALID_STRING_LENGTH);
txtEntryStorage[txtEntryIdx++] = { "CRA", Uint8::from_const_char(mrpRetryActiveStorage), strlen(mrpRetryActiveStorage) };
}
if (params.GetTcpSupported().HasValue())
{
size_t writtenCharactersNumber =
snprintf(tcpSupportedStorage, sizeof(tcpSupportedStorage), "%d", params.GetTcpSupported().Value());
VerifyOrReturnError((writtenCharactersNumber > 0) && (writtenCharactersNumber <= kKeyTcpSupportMaxLength),
CHIP_ERROR_INVALID_STRING_LENGTH);
txtEntryStorage[txtEntryIdx++] = { "T", reinterpret_cast<const uint8_t *>(tcpSupportedStorage),
strlen(tcpSupportedStorage) };
}
return CHIP_NO_ERROR;
}
CHIP_ERROR DiscoveryImplPlatform::Advertise(const CommissionAdvertisingParameters & params)
{
CHIP_ERROR error = CHIP_NO_ERROR;
DnssdService service;
// add newline to lengths for TXT entries
char discriminatorBuf[kKeyDiscriminatorMaxLength + 1];
char vendorProductBuf[kKeyVendorProductMaxLength + 1];
char commissioningModeBuf[kKeyCommissioningModeMaxLength + 1];
char deviceTypeBuf[kKeyDeviceTypeMaxLength + 1];
char deviceNameBuf[kKeyDeviceNameMaxLength + 1];
char rotatingIdBuf[kKeyRotatingIdMaxLength + 1];
char pairingHintBuf[kKeyPairingHintMaxLength + 1];
char pairingInstrBuf[kKeyPairingInstructionMaxLength + 1];
char mrpRetryIntervalIdleBuf[kTxtRetryIntervalIdleMaxLength + 1];
char mrpRetryIntervalActiveBuf[kTxtRetryIntervalActiveMaxLength + 1];
char tcpSupportedBuf[kKeyTcpSupportMaxLength + 1];
// size of textEntries array should be count of Bufs above
TextEntry textEntries[CommissionAdvertisingParameters::kTxtMaxNumber];
size_t textEntrySize = 0;
// add null-character to the subtypes
char shortDiscriminatorSubtype[kSubTypeShortDiscriminatorMaxLength + 1];
char longDiscriminatorSubtype[kSubTypeLongDiscriminatorMaxLength + 1];
char vendorSubType[kSubTypeVendorMaxLength + 1];
char commissioningModeSubType[kSubTypeCommissioningModeMaxLength + 1];
char deviceTypeSubType[kSubTypeDeviceTypeMaxLength + 1];
// size of subTypes array should be count of SubTypes above
const char * subTypes[Commissionable::kSubTypeMaxNumber];
size_t subTypeSize = 0;
if (!mDnssdInitialized)
{
return CHIP_ERROR_INCORRECT_STATE;
}
error = MakeHostName(service.mHostName, sizeof(service.mHostName), params.GetMac());
if (error != CHIP_NO_ERROR)
{
ChipLogError(Discovery, "Failed to create dnssd hostname: %s", ErrorStr(error));
return error;
}
ReturnErrorOnFailure(GetCommissionableInstanceName(service.mName, sizeof(service.mName)));
if (params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode)
{
strncpy(service.mType, kCommissionableServiceName, sizeof(service.mType));
}
else
{
strncpy(service.mType, kCommissionerServiceName, sizeof(service.mType));
}
service.mProtocol = DnssdServiceProtocol::kDnssdProtocolUdp;
if (params.GetVendorId().HasValue())
{
if (params.GetProductId().HasValue())
{
snprintf(vendorProductBuf, sizeof(vendorProductBuf), "%u+%u", params.GetVendorId().Value(),
params.GetProductId().Value());
}
else
{
snprintf(vendorProductBuf, sizeof(vendorProductBuf), "%u", params.GetVendorId().Value());
}
textEntries[textEntrySize++] = { "VP", reinterpret_cast<const uint8_t *>(vendorProductBuf),
strnlen(vendorProductBuf, sizeof(vendorProductBuf)) };
}
if (params.GetDeviceType().HasValue())
{
snprintf(deviceTypeBuf, sizeof(deviceTypeBuf), "%u", params.GetDeviceType().Value());
textEntries[textEntrySize++] = { "DT", reinterpret_cast<const uint8_t *>(deviceTypeBuf),
strnlen(deviceTypeBuf, sizeof(deviceTypeBuf)) };
}
if (params.GetDeviceName().HasValue())
{
snprintf(deviceNameBuf, sizeof(deviceNameBuf), "%s", params.GetDeviceName().Value());
textEntries[textEntrySize++] = { "DN", reinterpret_cast<const uint8_t *>(deviceNameBuf),
strnlen(deviceNameBuf, sizeof(deviceNameBuf)) };
}
AddCommonTxtElements<CommissionAdvertisingParameters>(params, mrpRetryIntervalIdleBuf, mrpRetryIntervalActiveBuf,
tcpSupportedBuf, textEntries, textEntrySize);
// Following fields are for nodes and not for commissioners
if (params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode)
{
snprintf(discriminatorBuf, sizeof(discriminatorBuf), "%u", params.GetLongDiscriminator());
textEntries[textEntrySize++] = { "D", reinterpret_cast<const uint8_t *>(discriminatorBuf),
strnlen(discriminatorBuf, sizeof(discriminatorBuf)) };
snprintf(commissioningModeBuf, sizeof(commissioningModeBuf), "%u", static_cast<int>(params.GetCommissioningMode()));
textEntries[textEntrySize++] = { "CM", reinterpret_cast<const uint8_t *>(commissioningModeBuf),
strnlen(commissioningModeBuf, sizeof(commissioningModeBuf)) };
if (params.GetRotatingId().HasValue())
{
snprintf(rotatingIdBuf, sizeof(rotatingIdBuf), "%s", params.GetRotatingId().Value());
textEntries[textEntrySize++] = { "RI", reinterpret_cast<const uint8_t *>(rotatingIdBuf),
strnlen(rotatingIdBuf, sizeof(rotatingIdBuf)) };
}
if (params.GetPairingHint().HasValue())
{
snprintf(pairingHintBuf, sizeof(pairingHintBuf), "%u", params.GetPairingHint().Value());
textEntries[textEntrySize++] = { "PH", reinterpret_cast<const uint8_t *>(pairingHintBuf),
strnlen(pairingHintBuf, sizeof(pairingHintBuf)) };
}
if (params.GetPairingInstr().HasValue())
{
snprintf(pairingInstrBuf, sizeof(pairingInstrBuf), "%s", params.GetPairingInstr().Value());
textEntries[textEntrySize++] = { "PI", reinterpret_cast<const uint8_t *>(pairingInstrBuf),
strnlen(pairingInstrBuf, sizeof(pairingInstrBuf)) };
}
if (MakeServiceSubtype(shortDiscriminatorSubtype, sizeof(shortDiscriminatorSubtype),
DiscoveryFilter(DiscoveryFilterType::kShort, params.GetShortDiscriminator())) == CHIP_NO_ERROR)
{
subTypes[subTypeSize++] = shortDiscriminatorSubtype;
}
if (MakeServiceSubtype(longDiscriminatorSubtype, sizeof(longDiscriminatorSubtype),
DiscoveryFilter(DiscoveryFilterType::kLong, params.GetLongDiscriminator())) == CHIP_NO_ERROR)
{
subTypes[subTypeSize++] = longDiscriminatorSubtype;
}
if ((params.GetCommissioningMode() != CommissioningMode::kDisabled) &&
(MakeServiceSubtype(commissioningModeSubType, sizeof(commissioningModeSubType),
DiscoveryFilter(DiscoveryFilterType::kCommissioningMode)) == CHIP_NO_ERROR))
{
subTypes[subTypeSize++] = commissioningModeSubType;
}
}
if (params.GetVendorId().HasValue())
{
if (MakeServiceSubtype(vendorSubType, sizeof(vendorSubType),
DiscoveryFilter(DiscoveryFilterType::kVendor, params.GetVendorId().Value())) == CHIP_NO_ERROR)
{
subTypes[subTypeSize++] = vendorSubType;
}
}
if (params.GetDeviceType().HasValue())
{
if (MakeServiceSubtype(deviceTypeSubType, sizeof(deviceTypeSubType),
DiscoveryFilter(DiscoveryFilterType::kDeviceType, params.GetDeviceType().Value())) == CHIP_NO_ERROR)
{
subTypes[subTypeSize++] = deviceTypeSubType;
}
}
service.mTextEntries = textEntries;
service.mTextEntrySize = textEntrySize;
service.mPort = params.GetPort();
service.mInterface = INET_NULL_INTERFACEID;
service.mSubTypes = subTypes;
service.mSubTypeSize = subTypeSize;
service.mAddressType = Inet::IPAddressType::kAny;
error = ChipDnssdPublishService(&service);
if (error == CHIP_NO_ERROR)
{
if (params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode)
{
mCommissionableNodeAdvertisingParams = params;
mIsCommissionableNodePublishing = true;
}
else
{
mCommissionerAdvertisingParams = params;
mIsCommissionerPublishing = true;
}
}
#ifdef DETAIL_LOGGING
PrintEntries(&service);
#endif
return error;
}
#ifdef DETAIL_LOGGING
void DiscoveryImplPlatform::PrintEntries(const DnssdService * service)
{
printf("printEntries port=%d, mTextEntrySize=%d, mSubTypeSize=%d\n", (int) (service->mPort), (int) (service->mTextEntrySize),
(int) (service->mSubTypeSize));
for (int i = 0; i < (int) service->mTextEntrySize; i++)
{
printf(" entry [%d] : %s %s\n", i, service->mTextEntries[i].mKey, (char *) (service->mTextEntries[i].mData));
}
for (int i = 0; i < (int) service->mSubTypeSize; i++)
{
printf(" type [%d] : %s\n", i, service->mSubTypes[i]);
}
}
#endif
CHIP_ERROR DiscoveryImplPlatform::Advertise(const OperationalAdvertisingParameters & params)
{
DnssdService service;
CHIP_ERROR error = CHIP_NO_ERROR;
char compressedFabricIdSub[kSubTypeCompressedFabricIdMaxLength + 1];
const char * subTypes[Operational::kSubTypeMaxNumber];
size_t subTypeSize = 0;
mOperationalAdvertisingParams = params;
// TODO: There may be multilple device/fabric ids after multi-admin.
char mrpRetryIntervalIdleBuf[kTxtRetryIntervalIdleMaxLength + 1];
char mrpRetryIntervalActiveBuf[kTxtRetryIntervalActiveMaxLength + 1];
char tcpSupportedBuf[kKeyTcpSupportMaxLength + 1];
TextEntry txtEntries[OperationalAdvertisingParameters::kTxtMaxNumber];
size_t textEntrySize = 0;
ReturnLogErrorOnFailure(AddCommonTxtElements(params, mrpRetryIntervalIdleBuf, mrpRetryIntervalActiveBuf, tcpSupportedBuf,
txtEntries, textEntrySize));
if (MakeServiceSubtype(compressedFabricIdSub, sizeof(compressedFabricIdSub),
DiscoveryFilter(DiscoveryFilterType::kCompressedFabricId, params.GetPeerId().GetCompressedFabricId())) ==
CHIP_NO_ERROR)
{
subTypes[subTypeSize++] = compressedFabricIdSub;
}
error = MakeHostName(service.mHostName, sizeof(service.mHostName), params.GetMac());
if (error != CHIP_NO_ERROR)
{
ChipLogError(Discovery, "Failed to create dnssd hostname: %s", ErrorStr(error));
return error;
}
ReturnErrorOnFailure(MakeInstanceName(service.mName, sizeof(service.mName), params.GetPeerId()));
strncpy(service.mType, kOperationalServiceName, sizeof(service.mType));
service.mProtocol = DnssdServiceProtocol::kDnssdProtocolTcp;
service.mPort = params.GetPort();
service.mTextEntries = txtEntries;
service.mTextEntrySize = textEntrySize;
service.mInterface = INET_NULL_INTERFACEID;
service.mAddressType = Inet::IPAddressType::kAny;
service.mSubTypes = subTypes;
service.mSubTypeSize = subTypeSize;
error = ChipDnssdPublishService(&service);
if (error == CHIP_NO_ERROR)
{
mIsOperationalPublishing = true;
}
return error;
}
CHIP_ERROR DiscoveryImplPlatform::RemoveServices()
{
ReturnErrorOnFailure(ChipDnssdRemoveServices());
mIsOperationalPublishing = false;
mIsCommissionableNodePublishing = false;
mIsCommissionerPublishing = false;
return CHIP_NO_ERROR;
}
CHIP_ERROR DiscoveryImplPlatform::FinalizeServiceUpdate()
{
return ChipDnssdFinalizeServiceUpdate();
}
CHIP_ERROR DiscoveryImplPlatform::ResolveNodeId(const PeerId & peerId, Inet::IPAddressType type)
{
ReturnErrorOnFailure(InitImpl());
#if CHIP_CONFIG_MDNS_CACHE_SIZE > 0
Inet::IPAddress addr;
uint16_t port;
Inet::InterfaceId iface;
/* see if the entry is cached and use it.... */
if (sDnssdCache.Lookup(peerId, addr, port, iface) == CHIP_NO_ERROR)
{
ResolvedNodeData nodeData;
nodeData.mInterfaceId = iface;
nodeData.mPort = port;
nodeData.mAddress = addr;
nodeData.mPeerId = peerId;
mResolverDelegate->OnNodeIdResolved(nodeData);
return CHIP_NO_ERROR;
}
#endif
DnssdService service;
ReturnErrorOnFailure(MakeInstanceName(service.mName, sizeof(service.mName), peerId));
strncpy(service.mType, kOperationalServiceName, sizeof(service.mType));
service.mProtocol = DnssdServiceProtocol::kDnssdProtocolTcp;
service.mAddressType = type;
return ChipDnssdResolve(&service, INET_NULL_INTERFACEID, HandleNodeIdResolve, this);
}
void DiscoveryImplPlatform::HandleNodeBrowse(void * context, DnssdService * services, size_t servicesSize, CHIP_ERROR error)
{
for (size_t i = 0; i < servicesSize; ++i)
{
// For some platforms browsed services are already resolved, so verify if resolve is really needed or call resolve callback
if (!services[i].mAddress.HasValue())
{
ChipDnssdResolve(&services[i], services[i].mInterface, HandleNodeResolve, context);
}
else
{
HandleNodeResolve(context, &services[i], error);
}
}
}
void DiscoveryImplPlatform::HandleNodeResolve(void * context, DnssdService * result, CHIP_ERROR error)
{
if (error != CHIP_NO_ERROR)
{
return;
}
DiscoveryImplPlatform * mgr = static_cast<DiscoveryImplPlatform *>(context);
DiscoveredNodeData data;
Platform::CopyString(data.hostName, result->mHostName);
if (result->mAddress.HasValue() && data.numIPs < DiscoveredNodeData::kMaxIPAddresses)
{
data.ipAddress[data.numIPs] = result->mAddress.Value();
data.interfaceId[data.numIPs] = result->mInterface;
data.numIPs++;
}
data.port = result->mPort;
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->OnNodeDiscoveryComplete(data);
}
CHIP_ERROR DiscoveryImplPlatform::FindCommissionableNodes(DiscoveryFilter filter)
{
ReturnErrorOnFailure(InitImpl());
char serviceName[kMaxCommisisonableServiceNameSize];
ReturnErrorOnFailure(MakeServiceTypeName(serviceName, sizeof(serviceName), filter, DiscoveryType::kCommissionableNode));
return ChipDnssdBrowse(serviceName, DnssdServiceProtocol::kDnssdProtocolUdp, Inet::IPAddressType::kAny, INET_NULL_INTERFACEID,
HandleNodeBrowse, this);
}
CHIP_ERROR DiscoveryImplPlatform::FindCommissioners(DiscoveryFilter filter)
{
ReturnErrorOnFailure(InitImpl());
char serviceName[kMaxCommisisonerServiceNameSize];
ReturnErrorOnFailure(MakeServiceTypeName(serviceName, sizeof(serviceName), filter, DiscoveryType::kCommissionerNode));
return ChipDnssdBrowse(serviceName, DnssdServiceProtocol::kDnssdProtocolUdp, Inet::IPAddressType::kAny, INET_NULL_INTERFACEID,
HandleNodeBrowse, this);
}
void DiscoveryImplPlatform::HandleNodeIdResolve(void * context, DnssdService * result, CHIP_ERROR error)
{
DiscoveryImplPlatform * mgr = static_cast<DiscoveryImplPlatform *>(context);
if (mgr->mResolverDelegate == nullptr)
{
return;
}
if (error != CHIP_NO_ERROR)
{
ChipLogError(Discovery, "Node ID resolved failed with %s", chip::ErrorStr(error));
mgr->mResolverDelegate->OnNodeIdResolutionFailed(PeerId(), error);
return;
}
if (result == nullptr)
{
ChipLogError(Discovery, "Node ID resolve not found");
mgr->mResolverDelegate->OnNodeIdResolutionFailed(PeerId(), CHIP_ERROR_UNKNOWN_RESOURCE_ID);
return;
}
ResolvedNodeData nodeData;
error = ExtractIdFromInstanceName(result->mName, &nodeData.mPeerId);
if (error != CHIP_NO_ERROR)
{
ChipLogError(Discovery, "Node ID resolved failed with %s", chip::ErrorStr(error));
mgr->mResolverDelegate->OnNodeIdResolutionFailed(PeerId(), error);
return;
}
#if CHIP_CONFIG_MDNS_CACHE_SIZE > 0
// TODO -- define appropriate TTL, for now use 2000 msec (rfc default)
// figure out way to use TTL value from mDNS packet in future update
error = mgr->sDnssdCache.Insert(nodeData.mPeerId, result->mAddress.Value(), result->mPort, result->mInterface, 2 * 1000);
if (CHIP_NO_ERROR != error)
{
ChipLogError(Discovery, "DnssdCache insert failed with %s", chip::ErrorStr(error));
}
#endif
Platform::CopyString(nodeData.mHostName, result->mHostName);
nodeData.mInterfaceId = result->mInterface;
nodeData.mAddress = result->mAddress.ValueOr({});
nodeData.mPort = result->mPort;
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, nodeData);
}
nodeData.LogNodeIdResolved();
mgr->mResolverDelegate->OnNodeIdResolved(nodeData);
}
DiscoveryImplPlatform & DiscoveryImplPlatform::GetInstance()
{
return sManager;
}
ServiceAdvertiser & chip::Dnssd::ServiceAdvertiser::Instance()
{
return DiscoveryImplPlatform::GetInstance();
}
Resolver & chip::Dnssd::Resolver::Instance()
{
return DiscoveryImplPlatform::GetInstance();
}
} // namespace Dnssd
} // namespace chip