diff --git a/src/platform/Tizen/DnssdImpl.cpp b/src/platform/Tizen/DnssdImpl.cpp index 4568a1cf05eeee..f59e48b19d8407 100644 --- a/src/platform/Tizen/DnssdImpl.cpp +++ b/src/platform/Tizen/DnssdImpl.cpp @@ -41,6 +41,12 @@ namespace { constexpr uint8_t kDnssdKeyMaxSize = 32; +// The number of miliseconds which must elapse without a new "found" event before +// mDNS browsing is considered finished. We need this timeout because Tizen Native +// API does not deliver all-for-now signal (such signal is delivered by e.g. Avahi) +// and the browsing callback is called multiple times (once for each service found). +constexpr unsigned int kDnssdBrowseTimeoutMs = 250; + bool IsSupportedProtocol(DnssdServiceProtocol protocol) { return (protocol == DnssdServiceProtocol::kDnssdProtocolUdp) || (protocol == DnssdServiceProtocol::kDnssdProtocolTcp); @@ -109,6 +115,22 @@ gboolean RegisterAsync(GMainLoop * mainLoop, gpointer userData) return true; } +gboolean OnBrowseTimeout(void * userData) +{ + ChipLogDetail(DeviceLayer, "DNSsd %s: all for now", __func__); + + auto * bCtx = reinterpret_cast(userData); + + bCtx->MainLoopQuit(); + bCtx->mCallback(bCtx->mCbContext, bCtx->mServices.data(), bCtx->mServices.size(), CHIP_NO_ERROR); + + // After this point the context might be no longer valid + bCtx->mInstance->RemoveContext(bCtx); + + // This is a one-shot timer + return FALSE; +} + void OnBrowseAdd(BrowseContext * context, const char * type, const char * name, uint32_t interfaceId) { ChipLogDetail(DeviceLayer, "DNSsd %s: name: %s, type: %s, interfaceId: %u", __func__, name, type, interfaceId); @@ -143,8 +165,20 @@ void OnBrowse(dnssd_service_state_e state, dnssd_service_h service, void * data) auto bCtx = reinterpret_cast(data); int ret; - // Always stop browsing - bCtx->MainLoopQuit(); + // If there is already a timeout source, so we need to cancel it. + if (bCtx->mTimeoutSource != nullptr) + { + g_source_destroy(bCtx->mTimeoutSource); + g_source_unref(bCtx->mTimeoutSource); + } + + // Start a timer, so we could detect when there is no more on-browse events. + // The timeout callback function will be called in the same event loop as the + // browse callback (this one), so locking is not required. + auto * source = g_timeout_source_new(kDnssdBrowseTimeoutMs); + g_source_set_callback(source, OnBrowseTimeout, bCtx, nullptr); + g_source_attach(source, g_main_context_get_thread_default()); + bCtx->mTimeoutSource = source; char * type = nullptr; char * name = nullptr; @@ -173,23 +207,17 @@ void OnBrowse(dnssd_service_state_e state, dnssd_service_h service, void * data) OnBrowseRemove(bCtx, type, name, interfaceId); } - // For now, there is no way to wait for multiple services to be found. - // Darwin implementation just checks if kDNSServiceFlagsMoreComing is set or not, - // but it doesn't ensure that multiple services can be found. - bCtx->mCallback(bCtx->mCbContext, bCtx->mServices.data(), bCtx->mServices.size(), CHIP_NO_ERROR); - exit: + dnssd_destroy_remote_service(service); + if (ret != DNSSD_ERROR_NONE) { bCtx->mCallback(bCtx->mCbContext, nullptr, 0, GetChipError(ret)); + // After this point the context might be no longer valid + bCtx->mInstance->RemoveContext(bCtx); } - // After this point, the context might be no longer valid - bCtx->mInstance->RemoveContext(bCtx); - - dnssd_destroy_remote_service(service); - g_free(type); g_free(name); g_free(ifaceName); @@ -412,6 +440,11 @@ BrowseContext::BrowseContext(DnssdTizen * instance, const char * type, DnssdServ BrowseContext::~BrowseContext() { + if (mTimeoutSource != nullptr) + { + g_source_destroy(mTimeoutSource); + g_source_unref(mTimeoutSource); + } if (mIsBrowsing) { dnssd_cancel_browse_service(mBrowserHandle); diff --git a/src/platform/Tizen/DnssdImpl.h b/src/platform/Tizen/DnssdImpl.h index 28bcf313c443f5..9163a21dd36b46 100755 --- a/src/platform/Tizen/DnssdImpl.h +++ b/src/platform/Tizen/DnssdImpl.h @@ -80,6 +80,9 @@ struct BrowseContext : public GenericContext void * mCbContext; dnssd_browser_h mBrowserHandle = 0; + // The timeout source used to stop browsing + GSource * mTimeoutSource = nullptr; + std::vector mServices; bool mIsBrowsing = false;