From 170793414169e3fcd30d59efcf7e3201f6f21944 Mon Sep 17 00:00:00 2001 From: Arkadiusz Bokowy Date: Tue, 2 Aug 2022 20:15:19 +0200 Subject: [PATCH] [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. --- src/platform/Tizen/DnssdImpl.cpp | 57 +++++++++++++++++++++++++------- src/platform/Tizen/DnssdImpl.h | 3 ++ 2 files changed, 48 insertions(+), 12 deletions(-) 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;