Skip to content

Commit a49b2bb

Browse files
authored
Allow to call mDNS browse callback more than once (#19554)
* [Tizen] Wait for mDNS on-browse events until timeout Tizen Native API dos not deliver all-for-now event (such event is delivered by e.g. Avahi), so it is impossible to tell when the mDNS browsing shall be considered finished. This commit adds timeout event which is delivered after 250ms from the last on-browse event. This allows Tizen platform to discover more than one mDNS service on local network. * Allow to call mDNS browse callback more than once This commit extends mDNS browsing callback to be called once per single mDNS service or all at once. In case when the callback might be called again, the internal proxy is not released. The callback could be called with the error code equal to: - CHIP_NO_ERROR - no errors; browsing is not done yet - CHIP_END_OF_INPUT - no errors; end of browsing - other - browsing error code * Fix DNS-SD unit test so it can resolve more than one address * Adopt OpenThread browsing to end-of-browse notification This will fix double-free error when more than one service was discovered by the OpenThread mDNS browsing.
1 parent 23223a1 commit a49b2bb

File tree

11 files changed

+72
-44
lines changed

11 files changed

+72
-44
lines changed

src/include/platform/ThreadStackManager.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ class GenericThreadStackManagerImpl_FreeRTOS;
6969
// Declaration of callback types corresponding to DnssdResolveCallback and DnssdBrowseCallback to avoid circular including.
7070
using DnsResolveCallback = void (*)(void * context, chip::Dnssd::DnssdService * result, const Span<Inet::IPAddress> & addresses,
7171
CHIP_ERROR error);
72-
using DnsBrowseCallback = void (*)(void * context, chip::Dnssd::DnssdService * services, size_t servicesSize, CHIP_ERROR error);
72+
using DnsBrowseCallback = void (*)(void * context, chip::Dnssd::DnssdService * services, size_t servicesSize, bool finalBrowse,
73+
CHIP_ERROR error);
7374
#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT
7475

7576
#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT

src/lib/dnssd/Discovery_ImplPlatform.cpp

+12-2
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,16 @@ static void HandleNodeIdResolve(void * context, DnssdService * result, const Spa
147147
proxy->Release();
148148
}
149149

150-
static void HandleNodeBrowse(void * context, DnssdService * services, size_t servicesSize, CHIP_ERROR error)
150+
static void HandleNodeBrowse(void * context, DnssdService * services, size_t servicesSize, bool finalBrowse, CHIP_ERROR error)
151151
{
152152
ResolverDelegateProxy * proxy = static_cast<ResolverDelegateProxy *>(context);
153153

154+
if (error != CHIP_NO_ERROR)
155+
{
156+
proxy->Release();
157+
return;
158+
}
159+
154160
for (size_t i = 0; i < servicesSize; ++i)
155161
{
156162
proxy->Retain();
@@ -165,7 +171,11 @@ static void HandleNodeBrowse(void * context, DnssdService * services, size_t ser
165171
HandleNodeResolve(context, &services[i], Span<Inet::IPAddress>(address, 1), error);
166172
}
167173
}
168-
proxy->Release();
174+
175+
if (finalBrowse)
176+
{
177+
proxy->Release();
178+
}
169179
}
170180

171181
CHIP_ERROR AddPtrRecord(DiscoveryFilter filter, const char ** entries, size_t & entriesCount, char * buffer, size_t bufferLen)

src/lib/dnssd/platform/Dnssd.h

+12-6
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ struct DnssdService
8787
* any pointer inside this structure.
8888
*
8989
* @param[in] context The context passed to ChipDnssdBrowse or ChipDnssdResolve.
90-
* @param[in] result The mdns resolve result, can be nullptr if error
90+
* @param[in] result The mDNS resolve result, can be nullptr if error
9191
* happens. The mAddress of this object will be ignored.
9292
* @param[in] addresses IP addresses that we resolved.
9393
* @param[in] error The error code.
@@ -102,13 +102,19 @@ using DnssdResolveCallback = void (*)(void * context, DnssdService * result, con
102102
* The callback function SHALL NOT take the ownership of the service pointer or
103103
* any pointer inside this structure.
104104
*
105+
* The callback function SHALL release its internal resources only when the
106+
* finalBrowse is true or when the error is not CHIP_NO_ERROR. Calling this
107+
* callback function again in either case is a programming error.
108+
*
105109
* @param[in] context The context passed to ChipDnssdBrowse or ChipDnssdResolve.
106110
* @param[in] services The service list, can be nullptr.
107111
* @param[in] servicesSize The size of the service list.
112+
* @param[in] finalBrowse When true, this is the last callback for this browse.
108113
* @param[in] error The error code.
109114
*
110115
*/
111-
using DnssdBrowseCallback = void (*)(void * context, DnssdService * services, size_t servicesSize, CHIP_ERROR error);
116+
using DnssdBrowseCallback = void (*)(void * context, DnssdService * services, size_t servicesSize, bool finalBrowse,
117+
CHIP_ERROR error);
112118

113119
/**
114120
* The callback function for mDNS publish.
@@ -129,7 +135,7 @@ using DnssdPublishCallback = void (*)(void * context, const char * type, const c
129135
using DnssdAsyncReturnCallback = void (*)(void * context, CHIP_ERROR error);
130136

131137
/**
132-
* This function initializes the mdns module
138+
* This function initializes the mDNS module
133139
*
134140
* @param[in] initCallback The callback for notifying the initialization result.
135141
* @param[in] errorCallback The callback for notifying internal errors.
@@ -142,7 +148,7 @@ using DnssdAsyncReturnCallback = void (*)(void * context, CHIP_ERROR error);
142148
CHIP_ERROR ChipDnssdInit(DnssdAsyncReturnCallback initCallback, DnssdAsyncReturnCallback errorCallback, void * context);
143149

144150
/**
145-
* This function shuts down the mdns module
151+
* This function shuts down the mDNS module
146152
*/
147153
void ChipDnssdShutdown();
148154

@@ -189,7 +195,7 @@ CHIP_ERROR ChipDnssdPublishService(const DnssdService * service, DnssdPublishCal
189195
CHIP_ERROR ChipDnssdFinalizeServiceUpdate();
190196

191197
/**
192-
* This function browses the services published by mdns
198+
* This function browses the services published by mDNS
193199
*
194200
* @param[in] type The service type.
195201
* @param[in] protocol The service protocol.
@@ -207,7 +213,7 @@ CHIP_ERROR ChipDnssdBrowse(const char * type, DnssdServiceProtocol protocol, chi
207213
chip::Inet::InterfaceId interface, DnssdBrowseCallback callback, void * context);
208214

209215
/**
210-
* This function resolves the services published by mdns
216+
* This function resolves the services published by mDNS
211217
*
212218
* @param[in] browseResult The service entry returned by @ref ChipDnssdBrowse
213219
* @param[in] interface The interface to send queries.

src/platform/Darwin/DnssdContexts.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -285,13 +285,13 @@ BrowseContext::BrowseContext(void * cbContext, DnssdBrowseCallback cb, DnssdServ
285285
void BrowseContext::DispatchFailure(DNSServiceErrorType err)
286286
{
287287
ChipLogError(Discovery, "Mdns: Browse failure (%s)", Error::ToString(err));
288-
callback(context, nullptr, 0, CHIP_ERROR_INTERNAL);
288+
callback(context, nullptr, 0, true, CHIP_ERROR_INTERNAL);
289289
MdnsContexts::GetInstance().Remove(this);
290290
}
291291

292292
void BrowseContext::DispatchSuccess()
293293
{
294-
callback(context, services.data(), services.size(), CHIP_NO_ERROR);
294+
callback(context, services.data(), services.size(), true, CHIP_NO_ERROR);
295295
MdnsContexts::GetInstance().Remove(this);
296296
}
297297

src/platform/ESP32/DnssdImpl.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ CHIP_ERROR OnBrowseDone(BrowseContext * ctx)
314314
}
315315
}
316316
exit:
317-
ctx->mBrowseCb(ctx->mCbContext, ctx->mServices, ctx->mServiceSize, error);
317+
ctx->mBrowseCb(ctx->mCbContext, ctx->mServices, ctx->mServiceSize, true, error);
318318
return RemoveMdnsQuery(reinterpret_cast<GenericContext *>(ctx));
319319
}
320320

src/platform/Linux/DnssdImpl.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ void MdnsAvahi::HandleBrowse(AvahiServiceBrowser * browser, AvahiIfIndex interfa
642642
break;
643643
case AVAHI_BROWSER_ALL_FOR_NOW:
644644
ChipLogProgress(DeviceLayer, "Avahi browse: all for now");
645-
context->mCallback(context->mContext, context->mServices.data(), context->mServices.size(), CHIP_NO_ERROR);
645+
context->mCallback(context->mContext, context->mServices.data(), context->mServices.size(), true, CHIP_NO_ERROR);
646646
avahi_service_browser_free(browser);
647647
chip::Platform::Delete(context);
648648
break;

src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.cpp

+9-16
Original file line numberDiff line numberDiff line change
@@ -2522,15 +2522,15 @@ template <class ImplClass>
25222522
void GenericThreadStackManagerImpl_OpenThread<ImplClass>::DispatchBrowseEmpty(intptr_t context)
25232523
{
25242524
auto * dnsResult = reinterpret_cast<DnsResult *>(context);
2525-
ThreadStackMgrImpl().mDnsBrowseCallback(dnsResult->context, nullptr, 0, dnsResult->error);
2525+
ThreadStackMgrImpl().mDnsBrowseCallback(dnsResult->context, nullptr, 0, true, dnsResult->error);
25262526
Platform::Delete<DnsResult>(dnsResult);
25272527
}
25282528

25292529
template <class ImplClass>
25302530
void GenericThreadStackManagerImpl_OpenThread<ImplClass>::DispatchBrowse(intptr_t context)
25312531
{
25322532
auto * dnsResult = reinterpret_cast<DnsResult *>(context);
2533-
ThreadStackMgrImpl().mDnsBrowseCallback(dnsResult->context, &dnsResult->mMdnsService, 1, dnsResult->error);
2533+
ThreadStackMgrImpl().mDnsBrowseCallback(dnsResult->context, &dnsResult->mMdnsService, 1, false, dnsResult->error);
25342534
Platform::Delete<DnsResult>(dnsResult);
25352535
}
25362536

@@ -2547,8 +2547,7 @@ void GenericThreadStackManagerImpl_OpenThread<ImplClass>::OnDnsBrowseResult(otEr
25472547
// each entry consists of txt_entry_size (1B) + txt_entry_key + "=" + txt_entry_data
25482548
uint8_t txtBuffer[kMaxDnsServiceTxtEntriesNumber + kTotalDnsServiceTxtBufferSize];
25492549
otDnsServiceInfo serviceInfo;
2550-
uint16_t index = 0;
2551-
bool wasAnythingBrowsed = false;
2550+
uint16_t index = 0;
25522551

25532552
if (ThreadStackMgrImpl().mDnsBrowseCallback == nullptr)
25542553
{
@@ -2574,18 +2573,16 @@ void GenericThreadStackManagerImpl_OpenThread<ImplClass>::OnDnsBrowseResult(otEr
25742573

25752574
VerifyOrExit(error == CHIP_NO_ERROR, );
25762575

2577-
DnsResult * dnsResult = Platform::New<DnsResult>(aContext, MapOpenThreadError(aError));
2576+
DnsResult * dnsResult = Platform::New<DnsResult>(aContext, CHIP_NO_ERROR);
25782577
error = FromOtDnsResponseToMdnsData(serviceInfo, type, dnsResult->mMdnsService, dnsResult->mServiceTxtEntry);
25792578
if (CHIP_NO_ERROR == error)
25802579
{
2581-
// Invoke callback for every service one by one instead of for the whole list due to large memory size needed to
2582-
// allocate on
2583-
// stack.
2580+
// Invoke callback for every service one by one instead of for the whole
2581+
// list due to large memory size needed to allocate on stack.
25842582
static_assert(ArraySize(dnsResult->mMdnsService.mName) >= ArraySize(serviceName),
25852583
"The target buffer must be big enough");
25862584
Platform::CopyString(dnsResult->mMdnsService.mName, serviceName);
25872585
DeviceLayer::PlatformMgr().ScheduleWork(DispatchBrowse, reinterpret_cast<intptr_t>(dnsResult));
2588-
wasAnythingBrowsed = true;
25892586
}
25902587
else
25912588
{
@@ -2595,13 +2592,9 @@ void GenericThreadStackManagerImpl_OpenThread<ImplClass>::OnDnsBrowseResult(otEr
25952592
}
25962593

25972594
exit:
2598-
2599-
// In case no service was found invoke callback to notify about failure. In other case it was already called before.
2600-
if (!wasAnythingBrowsed)
2601-
{
2602-
DnsResult * dnsResult = Platform::New<DnsResult>(aContext, MapOpenThreadError(aError));
2603-
DeviceLayer::PlatformMgr().ScheduleWork(DispatchBrowseEmpty, reinterpret_cast<intptr_t>(dnsResult));
2604-
}
2595+
// Invoke callback to notify about end-of-browse or failure
2596+
DnsResult * dnsResult = Platform::New<DnsResult>(aContext, error);
2597+
DeviceLayer::PlatformMgr().ScheduleWork(DispatchBrowseEmpty, reinterpret_cast<intptr_t>(dnsResult));
26052598
}
26062599

26072600
template <class ImplClass>

src/platform/Tizen/DnssdImpl.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ gboolean OnBrowseTimeout(void * userData)
124124
auto * bCtx = reinterpret_cast<BrowseContext *>(userData);
125125

126126
bCtx->MainLoopQuit();
127-
bCtx->mCallback(bCtx->mCbContext, bCtx->mServices.data(), bCtx->mServices.size(), CHIP_NO_ERROR);
127+
bCtx->mCallback(bCtx->mCbContext, bCtx->mServices.data(), bCtx->mServices.size(), true, CHIP_NO_ERROR);
128128

129129
// After this point the context might be no longer valid
130130
bCtx->mInstance->RemoveContext(bCtx);
@@ -215,7 +215,7 @@ void OnBrowse(dnssd_service_state_e state, dnssd_service_h service, void * data)
215215

216216
if (ret != DNSSD_ERROR_NONE)
217217
{
218-
bCtx->mCallback(bCtx->mCbContext, nullptr, 0, GetChipError(ret));
218+
bCtx->mCallback(bCtx->mCbContext, nullptr, 0, true, GetChipError(ret));
219219
// After this point the context might be no longer valid
220220
bCtx->mInstance->RemoveContext(bCtx);
221221
}
@@ -614,7 +614,7 @@ CHIP_ERROR DnssdTizen::Browse(const char * type, DnssdServiceProtocol protocol,
614614
exit:
615615
if (err != CHIP_NO_ERROR)
616616
{ // Notify caller about error
617-
callback(context, nullptr, 0, err);
617+
callback(context, nullptr, 0, true, err);
618618
RemoveContext(browseCtx);
619619
}
620620
return err;

src/platform/android/DnssdImpl.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ void HandleBrowse(jobjectArray instanceName, jstring serviceType, jlong callback
377377
const auto dispatch = [callbackHandle, contextHandle](CHIP_ERROR error, DnssdService * service = nullptr, size_t size = 0) {
378378
DeviceLayer::StackLock lock;
379379
DnssdBrowseCallback callback = reinterpret_cast<DnssdBrowseCallback>(callbackHandle);
380-
callback(reinterpret_cast<void *>(contextHandle), service, size, error);
380+
callback(reinterpret_cast<void *>(contextHandle), service, size, true, error);
381381
};
382382

383383
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();

src/platform/tests/TestDnssd.cpp

+28-10
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ using chip::Dnssd::DnssdService;
1414
using chip::Dnssd::DnssdServiceProtocol;
1515
using chip::Dnssd::TextEntry;
1616

17+
static unsigned int gBrowsedServicesCount = 0;
18+
static unsigned int gResolvedServicesCount = 0;
19+
static bool gEndOfInput = false;
20+
1721
static void HandleResolve(void * context, DnssdService * result, const chip::Span<chip::Inet::IPAddress> & addresses,
1822
CHIP_ERROR error)
1923
{
@@ -22,31 +26,45 @@ static void HandleResolve(void * context, DnssdService * result, const chip::Spa
2226

2327
NL_TEST_ASSERT(suite, result != nullptr);
2428
NL_TEST_ASSERT(suite, error == CHIP_NO_ERROR);
29+
2530
if (!addresses.empty())
2631
{
2732
addresses.data()[0].ToString(addrBuf, sizeof(addrBuf));
28-
printf("Service at [%s]:%u\n", addrBuf, result->mPort);
33+
printf("Service[%u] at [%s]:%u\n", gResolvedServicesCount, addrBuf, result->mPort);
2934
}
35+
3036
NL_TEST_ASSERT(suite, result->mTextEntrySize == 1);
3137
NL_TEST_ASSERT(suite, strcmp(result->mTextEntries[0].mKey, "key") == 0);
3238
NL_TEST_ASSERT(suite, strcmp(reinterpret_cast<const char *>(result->mTextEntries[0].mData), "val") == 0);
3339

34-
chip::DeviceLayer::PlatformMgr().StopEventLoopTask();
35-
chip::DeviceLayer::PlatformMgr().Shutdown();
36-
exit(0);
40+
if (gBrowsedServicesCount == ++gResolvedServicesCount)
41+
{
42+
chip::DeviceLayer::PlatformMgr().StopEventLoopTask();
43+
chip::DeviceLayer::PlatformMgr().Shutdown();
44+
exit(0);
45+
}
3746
}
3847

39-
static void HandleBrowse(void * context, DnssdService * services, size_t servicesSize, CHIP_ERROR error)
48+
static void HandleBrowse(void * context, DnssdService * services, size_t servicesSize, bool finalBrowse, CHIP_ERROR error)
4049
{
4150
nlTestSuite * suite = static_cast<nlTestSuite *>(context);
4251

52+
// Make sure that we will not be called again after end-of-input is set
53+
NL_TEST_ASSERT(suite, gEndOfInput == false);
4354
NL_TEST_ASSERT(suite, error == CHIP_NO_ERROR);
44-
if (services)
55+
56+
gBrowsedServicesCount += servicesSize;
57+
gEndOfInput = finalBrowse;
58+
59+
if (servicesSize > 0)
4560
{
46-
printf("Mdns service size %u\n", static_cast<unsigned int>(servicesSize));
47-
printf("Service name %s\n", services->mName);
48-
printf("Service type %s\n", services->mType);
49-
NL_TEST_ASSERT(suite, ChipDnssdResolve(services, chip::Inet::InterfaceId::Null(), HandleResolve, suite) == CHIP_NO_ERROR);
61+
printf("Browse mDNS service size %u\n", static_cast<unsigned int>(servicesSize));
62+
for (unsigned int i = 0; i < servicesSize; i++)
63+
{
64+
printf("Service[%u] name %s\n", i, services[i].mName);
65+
printf("Service[%u] type %s\n", i, services[i].mType);
66+
NL_TEST_ASSERT(suite, ChipDnssdResolve(&services[i], services[i].mInterface, HandleResolve, suite) == CHIP_NO_ERROR);
67+
}
5068
}
5169
}
5270

src/platform/webos/DnssdImpl.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,7 @@ void MdnsAvahi::HandleBrowse(AvahiServiceBrowser * browser, AvahiIfIndex interfa
640640
break;
641641
case AVAHI_BROWSER_ALL_FOR_NOW:
642642
ChipLogProgress(DeviceLayer, "Avahi browse: all for now");
643-
context->mCallback(context->mContext, context->mServices.data(), context->mServices.size(), CHIP_NO_ERROR);
643+
context->mCallback(context->mContext, context->mServices.data(), context->mServices.size(), true, CHIP_NO_ERROR);
644644
avahi_service_browser_free(browser);
645645
chip::Platform::Delete(context);
646646
break;

0 commit comments

Comments
 (0)