Skip to content

Commit

Permalink
Addressed review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
nivi-apple committed Sep 7, 2022
1 parent 8141df6 commit 6c85214
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 82 deletions.
79 changes: 71 additions & 8 deletions src/platform/Darwin/DnssdContexts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ void RegisterContext::DispatchFailure(DNSServiceErrorType err)
{
ChipLogError(Discovery, "Mdns: Register failure (%s)", Error::ToString(err));
callback(context, nullptr, nullptr, CHIP_ERROR_INTERNAL);
MdnsContexts::GetInstance().RemoveAllOfType(ContextType::RegisterRecord);
MdnsContexts::GetInstance().Remove(this);
}

Expand All @@ -273,25 +274,27 @@ void RegisterContext::DispatchSuccess()
callback(context, typeWithoutSubTypes.c_str(), mInstanceName.c_str(), CHIP_NO_ERROR);
}

RegisterRecordContext::RegisterRecordContext(DnssdPublishCallback cb, void * cbContext)
RegisterRecordContext::RegisterRecordContext(DnssdPublishCallback cb, void * cbContext, uint32_t interfaceId, const char * name,
const char * sType, const char * hostname, uint16_t port, uint16_t size,
const void * data)
{
type = ContextType::RegisterRecord;
context = cbContext;
callback = cb;
type = ContextType::RegisterRecord;
context = cbContext;
callback = cb;
mServiceInfo = chip::Platform::New<RegisterServiceInfo>(interfaceId, name, sType, hostname, port, size, data);
}

void RegisterRecordContext::DispatchFailure(DNSServiceErrorType err)
{
ChipLogError(Discovery, "Mdns: Register Record Failure (%s)", Error::ToString(err));
// Return CHIP_ERROR_MDNS_COLLISION error so that the caller can handle a name conflict
CHIP_ERROR error = (err == kDNSServiceErr_NameConflict) ? CHIP_ERROR_MDNS_COLLISION : CHIP_ERROR_INTERNAL;
callback(context, nullptr, error);
callback(context, nullptr, nullptr, Error::ToChipError(err));
chip::Platform::Delete(this->mServiceInfo);
MdnsContexts::GetInstance().Remove(this);
}

void RegisterRecordContext::DispatchSuccess()
{
MdnsContexts::GetInstance().Remove(this);
chip::Platform::Delete(this->mServiceInfo);
}

BrowseContext::BrowseContext(void * cbContext, DnssdBrowseCallback cb, DnssdServiceProtocol cbContextProtocol)
Expand Down Expand Up @@ -497,5 +500,65 @@ InterfaceInfo::~InterfaceInfo()
Platform::MemoryFree(const_cast<TextEntry *>(service.mTextEntries));
}

uint32_t RegisterServiceInfo::sCount = 0;

RegisterServiceInfo::RegisterServiceInfo()
{
mName = nullptr;
mType = nullptr;
mHostname = nullptr;
mData = nullptr;
mInterfaceId = 0;
mPort = 0;
mSize = 0;
}

RegisterServiceInfo::RegisterServiceInfo(uint32_t interfaceId, const char * name, const char * sType, const char * hostname,
uint16_t port, uint16_t size, const void * data)
{
mInterfaceId = interfaceId;
size_t len = strlen(name) + 1;
mName = (char *) chip::Platform::MemoryCalloc(len, sizeof(char *));
Platform::CopyString(mName, len, name);
len = strlen(sType) + 1;
mType = (char *) chip::Platform::MemoryCalloc(len, sizeof(char *));
Platform::CopyString(mType, len, sType);
len = strlen(hostname) + 1;
mHostname = (char *) chip::Platform::MemoryCalloc(len, sizeof(char *));
Platform::CopyString(mHostname, len, hostname);
mPort = port;
mSize = size;
mData = chip::Platform::MemoryCalloc(size, sizeof(void *));
if (mData != nullptr)
{
memcpy(mData, data, size);
}
RegisterServiceInfo::sCount++;
}

RegisterServiceInfo::~RegisterServiceInfo()
{
if (mName)
{
Platform::MemoryFree(const_cast<char *>(mName));
}
if (mType)
{
Platform::MemoryFree(const_cast<char *>(mType));
}
if (mHostname)
{
Platform::MemoryFree(const_cast<char *>(mHostname));
}
if (mData)
{
Platform::MemoryFree(mData);
}
mInterfaceId = 0;
mPort = 0;
mSize = 0;
RegisterServiceInfo::sCount--;
}

} // namespace Dnssd
} // namespace chip
172 changes: 101 additions & 71 deletions src/platform/Darwin/DnssdImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ std::string GetFullTypeWithSubTypes(const DnssdService * service)
return GetFullTypeWithSubTypes(service->mType, service->mProtocol, service->mSubTypes, service->mSubTypeSize);
}

std::string GetHostnameWithDomain(const char * hostname, const char * domain)
{
return std::string(hostname) + '.' + std::string(domain);
}

void LogOnFailure(const char * name, DNSServiceErrorType err)
{
if (kDNSServiceErr_NoError != err)
Expand Down Expand Up @@ -164,100 +169,131 @@ MdnsContexts MdnsContexts::sInstance;

namespace {

static void OnRegisterRecord(DNSServiceRef sdRef, DNSRecordRef recordRef, DNSServiceFlags flags, DNSServiceErrorType err,
void * context)
{
if (err != kDNSServiceErr_NoError)
{
ChipLogError(Discovery, "Mdns: %s Registered Record failed. Error: %d", __func__, err);
auto sdCtx = reinterpret_cast<RegisterRecordContext *>(context);
sdCtx->Finalize(err);
}
};

static void OnRegister(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType err, const char * name, const char * type,
const char * domain, void * context)
{
ChipLogDetail(Discovery, "Mdns: %s name: %s, type: %s, domain: %s, flags: %d Error %d", __func__, name, type, domain, flags,
err);
ChipLogDetail(Discovery, "Mdns: %s name: %s, type: %s, domain: %s, flags: %d", __func__, name, type, domain, flags);
auto sdCtx = reinterpret_cast<RegisterContext *>(context);
sdCtx->Finalize(err);
};

CHIP_ERROR RegisterService(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceId, const char * name, const char * type,
const char * domain, const char * hostname, uint16_t port, uint16_t txtLen, const void * txtRecord,
DNSServiceRegisterReply callback, RegisterContext * sdCtx)
static void OnRegisterRecord(DNSServiceRef sdRef, DNSRecordRef recordRef, DNSServiceFlags flags, DNSServiceErrorType err,
void * context)
{
auto err = DNSServiceRegister(&sdRef, flags, interfaceId, name, type, domain, hostname, ntohs(port), txtLen, txtRecord,
callback, sdCtx);
ChipLogProgress(Discovery, "Registering service %s on port %u with type: %s on interface id: %u hostname %s error: %d" PRIu32,
name, port, type, interfaceId, hostname, err);
VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err));
return MdnsContexts::GetInstance().Add(sdCtx, sdRef);
}
RegisterRecordContext * regCtx = reinterpret_cast<RegisterRecordContext *>(context);
if (RegisterServiceInfo::sCount == 1)
{
DNSServiceRef sdRefRegister = nullptr;
auto sdCtx = chip::Platform::New<RegisterContext>(regCtx->mServiceInfo->mType, regCtx->mServiceInfo->mName,
regCtx->callback, context);
if (sdCtx)
{
ChipLogProgress(Discovery, "Registering service %s on port %u with type: %s on interface id: %u hostname %s error: %d",
regCtx->mServiceInfo->mName, regCtx->mServiceInfo->mPort, regCtx->mServiceInfo->mType,
regCtx->mServiceInfo->mInterfaceId, regCtx->mServiceInfo->mHostname, err);

auto error = DNSServiceRegister(&sdRefRegister, kRegisterFlags, regCtx->mServiceInfo->mInterfaceId,
regCtx->mServiceInfo->mName, regCtx->mServiceInfo->mType, kLocalDot,
regCtx->mServiceInfo->mHostname, ntohs(regCtx->mServiceInfo->mPort),
regCtx->mServiceInfo->mSize, regCtx->mServiceInfo->mData, OnRegister, sdCtx);
if (error || sdRefRegister == nullptr)
{
ChipLogError(Discovery,
"Failed to register service %s on port %u with type: %s on interface id: %u hostname %s error: %d",
regCtx->mServiceInfo->mName, regCtx->mServiceInfo->mPort, regCtx->mServiceInfo->mType,
regCtx->mServiceInfo->mInterfaceId, regCtx->mServiceInfo->mHostname, err);
sdCtx->Finalize(error);
}
else
{
auto ret = MdnsContexts::GetInstance().Add(sdCtx, sdRefRegister);
if (ret != CHIP_NO_ERROR)
{
ChipLogError(Discovery, "Failed to add register service context");
}
}
}
}
regCtx->Finalize(err);
};

CHIP_ERROR RegisterRecord(RegisterRecordContext * registerRecordCtx, const char * type, uint32_t interfaceId, const char * hostname)
CHIP_ERROR RegisterRecord(void * context, DnssdPublishCallback callback, const char * type, uint32_t interfaceId,
const char * hostname, const char * name, uint16_t port, ScopedTXTRecord & record)
{
DNSServiceRef sdRef;
auto err = DNSServiceCreateConnection(&sdRef);
VerifyOrReturnError((kDNSServiceErr_NoError == err || sdRef != nullptr), registerRecordCtx->Finalize(err));

auto error = MdnsContexts::GetInstance().Add(registerRecordCtx, sdRef);
VerifyOrReturnError(CHIP_NO_ERROR == error, error);
// Get all the interface addresses
struct ifaddrs * ifaddr;
auto ret = getifaddrs(&ifaddr);
if (ret)
{
ChipLogError(Discovery, "Getting interface addresses failed %d.", ret);
freeifaddrs(ifaddr);
}
VerifyOrReturnError(ret == 0, registerRecordCtx->Finalize(ret));
VerifyOrReturnError(ret == 0, CHIP_ERROR_INTERNAL);

// Call DNSServiceRegisterRecord for each interface if interface id is of type any so we can register the address for each
// interface Otherwise just register record for the given interface id
bool isInterfaceIndexAny = (interfaceId == kDNSServiceInterfaceIndexAny);
for (struct ifaddrs * ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
bool shouldRegisterRecord =
(isInterfaceIndexAny || (!isInterfaceIndexAny && (if_nametoindex(ifa->ifa_name) == interfaceId)));
if (!shouldRegisterRecord)
{
continue;
}
if (ifa->ifa_addr->sa_family == AF_INET)
{
struct sockaddr_in * inaddr = (struct sockaddr_in *) ifa->ifa_addr;
bool shouldRegisterRecord =
(isInterfaceIndexAny || (!isInterfaceIndexAny && (if_nametoindex(ifa->ifa_name) == interfaceId)));
if (inaddr && shouldRegisterRecord)
if (!inaddr)
{
ChipLogDetail(Discovery, "Registering Record for hostname %s interface %d", hostname,
if_nametoindex(ifa->ifa_name));
DNSRecordRef dnsRecordRef;
err = DNSServiceRegisterRecord(sdRef, &dnsRecordRef, kRegisterRecordFlags, if_nametoindex(ifa->ifa_name), hostname,
kDNSServiceType_A, kDNSServiceClass_IN, 4, &inaddr->sin_addr, 0, OnRegisterRecord,
registerRecordCtx);
if (err || dnsRecordRef == nullptr)
{
freeifaddrs(ifaddr);
}
VerifyOrReturnError(kDNSServiceErr_NoError == err, registerRecordCtx->Finalize(err));
continue;
}

DNSServiceRef sdRef = nullptr;
auto err = DNSServiceCreateConnection(&sdRef);
VerifyOrReturnError((kDNSServiceErr_NoError == err || sdRef != nullptr), Error::ToChipError(err));

DNSRecordRef dnsRecordRef;
RegisterRecordContext * registerRecordCtx = chip::Platform::New<RegisterRecordContext>(
callback, context, interfaceId, name, type, hostname, port, record.size(), record.data());
VerifyOrReturnError(nullptr != registerRecordCtx, CHIP_ERROR_NO_MEMORY);
ChipLogDetail(Discovery, "Registering Record for hostname %s interface %d", hostname, if_nametoindex(ifa->ifa_name));
err = DNSServiceRegisterRecord(sdRef, &dnsRecordRef, kRegisterRecordFlags, if_nametoindex(ifa->ifa_name), hostname,
kDNSServiceType_A, kDNSServiceClass_IN, 4, &inaddr->sin_addr, 0, OnRegisterRecord,
registerRecordCtx);
if (err || dnsRecordRef == nullptr)
{
freeifaddrs(ifaddr);
}
VerifyOrReturnError(kDNSServiceErr_NoError == err, registerRecordCtx->Finalize(err));
auto error = MdnsContexts::GetInstance().Add(registerRecordCtx, sdRef);
VerifyOrReturnError(CHIP_NO_ERROR == error, error);
}
else if (ifa->ifa_addr->sa_family == AF_INET6)
{
struct sockaddr_in6 * inaddr = (struct sockaddr_in6 *) ifa->ifa_addr;
bool shouldRegisterRecord =
(isInterfaceIndexAny || (!isInterfaceIndexAny && (if_nametoindex(ifa->ifa_name) == interfaceId)));
if (inaddr && shouldRegisterRecord)
if (!inaddr)
{
ChipLogDetail(Discovery, "Registering Record for hostname %s interface %d", hostname,
if_nametoindex(ifa->ifa_name));
DNSRecordRef dnsRecordRef;
err = DNSServiceRegisterRecord(sdRef, &dnsRecordRef, kRegisterRecordFlags, if_nametoindex(ifa->ifa_name), hostname,
kDNSServiceType_AAAA, kDNSServiceClass_IN, 16, &inaddr->sin6_addr, 0,
OnRegisterRecord, registerRecordCtx);
if (err || dnsRecordRef == nullptr)
{
freeifaddrs(ifaddr);
}
VerifyOrReturnError(kDNSServiceErr_NoError == err, registerRecordCtx->Finalize(err));
continue;
}
DNSServiceRef sdRef = nullptr;
auto err = DNSServiceCreateConnection(&sdRef);
VerifyOrReturnError((kDNSServiceErr_NoError == err || sdRef != nullptr), Error::ToChipError(err));

DNSRecordRef dnsRecordRef;
RegisterRecordContext * registerRecordCtx = chip::Platform::New<RegisterRecordContext>(
callback, context, interfaceId, name, type, hostname, port, record.size(), record.data());
ChipLogDetail(Discovery, "Registering Record for hostname %s interface %d", hostname, if_nametoindex(ifa->ifa_name));
VerifyOrReturnError(nullptr != registerRecordCtx, CHIP_ERROR_NO_MEMORY);
err = DNSServiceRegisterRecord(sdRef, &dnsRecordRef, kRegisterRecordFlags, if_nametoindex(ifa->ifa_name), hostname,
kDNSServiceType_AAAA, kDNSServiceClass_IN, 16, &inaddr->sin6_addr, 0, OnRegisterRecord,
registerRecordCtx);
if (err || dnsRecordRef == nullptr)
{
freeifaddrs(ifaddr);
}
VerifyOrReturnError(kDNSServiceErr_NoError == err, registerRecordCtx->Finalize(err));
auto error = MdnsContexts::GetInstance().Add(registerRecordCtx, sdRef);
VerifyOrReturnError(CHIP_NO_ERROR == error, error);
}
}
freeifaddrs(ifaddr);
Expand All @@ -278,18 +314,10 @@ CHIP_ERROR Register(void * context, DnssdPublishCallback callback, uint32_t inte
return CHIP_NO_ERROR;
}

std::string hostnameStr = std::string(hostname) + '.' + kLocalDot;
hostname = hostnameStr.c_str();
RegisterRecordContext * registerRecordCtx = chip::Platform::New<RegisterRecordContext>(callback, context);
VerifyOrReturnError(nullptr != registerRecordCtx, CHIP_ERROR_NO_MEMORY);
auto err = RegisterRecord(registerRecordCtx, type, interfaceId, hostname);
hostname = GetHostnameWithDomain(hostname, kLocalDot).c_str();
auto err = RegisterRecord(context, callback, type, interfaceId, hostname, name, port, record);
VerifyOrReturnError(CHIP_NO_ERROR == err, err);

DNSServiceRef sdRef = nullptr;
sdCtx = chip::Platform::New<RegisterContext>(type, callback, context);
VerifyOrReturnError(nullptr != sdCtx, CHIP_ERROR_NO_MEMORY);
return RegisterService(sdRef, kRegisterFlags, interfaceId, name, type, kLocalDot, hostname, port, record.size(), record.data(),
OnRegister, sdCtx);
return err;
}

void OnBrowseAdd(BrowseContext * context, const char * name, const char * type, const char * domain, uint32_t interfaceId)
Expand Down Expand Up @@ -477,12 +505,14 @@ CHIP_ERROR ChipDnssdRemoveServices()
{
return CHIP_NO_ERROR;
}
ReturnErrorOnFailure(err);

err = MdnsContexts::GetInstance().RemoveAllOfType(ContextType::RegisterRecord);
if (CHIP_ERROR_KEY_NOT_FOUND == err)
{
return CHIP_NO_ERROR;
}
ReturnErrorOnFailure(err);
return err;
}

Expand Down
27 changes: 24 additions & 3 deletions src/platform/Darwin/DnssdImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ struct GenericContext
};

struct RegisterContext;
struct RegisterRecordContext;

class MdnsContexts
{
Expand Down Expand Up @@ -105,12 +104,34 @@ struct RegisterContext : public GenericContext
bool matches(const char * sType) { return mType.compare(sType) == 0; }
};

struct RegisterServiceInfo
{
RegisterServiceInfo();
RegisterServiceInfo(uint32_t interfaceId, const char * name, const char * sType, const char * hostname, uint16_t port,
uint16_t size, const void * data);
~RegisterServiceInfo();

uint32_t mInterfaceId;
char * mName;
char * mType;
char * mHostname;
uint16_t mPort;
uint16_t mSize;
void * mData;
static uint32_t sCount;
};

struct RegisterRecordContext : public GenericContext
{
// The publish callback is only called if we fail to register a record to notify the caller that an error
// has occured while trying to register the records. Note: if we were to add a public API to register the
// records, we can have a separate callback for this.
DnssdPublishCallback callback;
RegisterServiceInfo * mServiceInfo;

RegisterRecordContext(DnssdPublishCallback cb, void * cbContext);
virtual ~RegisterRecordContext(){};
RegisterRecordContext(DnssdPublishCallback cb, void * cbContext, uint32_t interfaceId, const char * name, const char * sType,
const char * hostname, uint16_t port, uint16_t size, const void * data);
virtual ~RegisterRecordContext() {}

void DispatchFailure(DNSServiceErrorType err) override;
void DispatchSuccess() override;
Expand Down
Loading

0 comments on commit 6c85214

Please sign in to comment.