Skip to content

Commit

Permalink
[Tizen] Wait for mDNS on-browse events until timeout (#21553)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
arkq authored Aug 11, 2022
1 parent 1a3737e commit c758e8b
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 12 deletions.
57 changes: 45 additions & 12 deletions src/platform/Tizen/DnssdImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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<BrowseContext *>(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);
Expand Down Expand Up @@ -143,8 +165,20 @@ void OnBrowse(dnssd_service_state_e state, dnssd_service_h service, void * data)
auto bCtx = reinterpret_cast<BrowseContext *>(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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions src/platform/Tizen/DnssdImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<DnssdService> mServices;
bool mIsBrowsing = false;

Expand Down

0 comments on commit c758e8b

Please sign in to comment.