Bonjour - need to keep resolvers around for updates

This commit is contained in:
Jonathan Bagg
2019-04-04 18:48:14 -04:00
parent c286fcd2c0
commit 8625824b8b
2 changed files with 89 additions and 66 deletions

View File

@@ -27,16 +27,38 @@
#include "qzeroconf.h" #include "qzeroconf.h"
#include "bonjour_p.h" #include "bonjour_p.h"
void Resolver::resolverReady()
{
DNSServiceErrorType err = DNSServiceProcessResult(DNSresolverRef);
if (err != kDNSServiceErr_NoError)
cleanUp();
}
void Resolver::addressReady()
{
DNSServiceErrorType err = DNSServiceProcessResult(DNSaddressRef);
if (err != kDNSServiceErr_NoError)
cleanUp();
}
void Resolver::cleanUp()
{
DNSServiceRefDeallocate(DNSresolverRef);
DNSServiceRefDeallocate(DNSaddressRef);
QString key = zcs->name() + QString::number(zcs->interfaceIndex());
ref->resolvers.remove(key);
delete this;
}
QZeroConfPrivate::QZeroConfPrivate(QZeroConf *parent) QZeroConfPrivate::QZeroConfPrivate(QZeroConf *parent)
{ {
pub = parent; pub = parent;
dnssRef = NULL; dnssRef = NULL;
browser = NULL; browser = NULL;
resolver = NULL;
bs = NULL; bs = NULL;
browserSocket = NULL; browserSocket = NULL;
resolverSocket = NULL;
addressSocket = NULL;
} }
void QZeroConfPrivate::bsRead() void QZeroConfPrivate::bsRead()
@@ -57,30 +79,28 @@ void QZeroConfPrivate::browserRead()
} }
} }
void QZeroConfPrivate::resolverRead() void QZeroConfPrivate::resolve(QZeroConfService zcs)
{
DNSServiceErrorType err = DNSServiceProcessResult(resolver);
if (err != kDNSServiceErr_NoError)
cleanUp(resolver);
}
void QZeroConfPrivate::resolve(void)
{ {
DNSServiceErrorType err; DNSServiceErrorType err;
Resolver *resolver = new Resolver;
QString key = zcs->name() + QString::number(zcs->interfaceIndex());
resolvers.insert(key, resolver);
resolver->ref = this;
resolver->zcs = zcs;
err = DNSServiceResolve(&resolver, kDNSServiceFlagsTimeout, work.head()->interfaceIndex(), work.head()->name().toUtf8(), work.head()->type().toUtf8(), work.head()->domain().toUtf8(), (DNSServiceResolveReply) resolverCallback, this); err = DNSServiceResolve(&resolver->DNSresolverRef, kDNSServiceFlagsTimeout, zcs->interfaceIndex(), zcs->name().toUtf8(), zcs->type().toUtf8(), zcs->domain().toUtf8(), (DNSServiceResolveReply) resolverCallback, resolver);
if (err == kDNSServiceErr_NoError) { if (err == kDNSServiceErr_NoError) {
int sockfd = DNSServiceRefSockFD(resolver); int sockfd = DNSServiceRefSockFD(resolver->DNSresolverRef);
if (sockfd == -1) { if (sockfd == -1) {
cleanUp(resolver); resolver->cleanUp();
} }
else { else {
resolverSocket = new QSocketNotifier(sockfd, QSocketNotifier::Read, this); resolver->resolverNotifier = new QSocketNotifier(sockfd, QSocketNotifier::Read);
connect(resolverSocket, SIGNAL(activated(int)), this, SLOT(resolverRead())); connect(resolver->resolverNotifier, &QSocketNotifier::activated, resolver, &Resolver::resolverReady);
} }
} }
else { else {
cleanUp(resolver); resolver->cleanUp();
} }
} }
@@ -115,17 +135,14 @@ void DNSSD_API QZeroConfPrivate::browseCallback(DNSServiceRef, DNSServiceFlags f
zcs->m_type = type; zcs->m_type = type;
zcs->m_domain = domain; zcs->m_domain = domain;
zcs->m_interfaceIndex = interfaceIndex; zcs->m_interfaceIndex = interfaceIndex;
if (!ref->work.size()) { ref->resolve(zcs);
ref->work.enqueue(zcs);
ref->resolve();
}
else
ref->work.enqueue(zcs);
} }
} }
else if (ref->pub->services.contains(key)) { else if (ref->pub->services.contains(key)) {
zcs = ref->pub->services[key]; zcs = ref->pub->services[key];
ref->pub->services.remove(key); ref->pub->services.remove(key);
if (ref->resolvers.contains(key))
ref->resolvers[key]->cleanUp();
emit ref->pub->serviceRemoved(zcs); emit ref->pub->serviceRemoved(zcs);
} }
} }
@@ -140,10 +157,10 @@ void DNSSD_API QZeroConfPrivate::resolverCallback(DNSServiceRef, DNSServiceFlags
const char *hostName, quint16 port, quint16 txtLen, const char *hostName, quint16 port, quint16 txtLen,
const char * txtRecord, void *userdata) const char * txtRecord, void *userdata)
{ {
QZeroConfPrivate *ref = static_cast<QZeroConfPrivate *>(userdata); Resolver *resolver = static_cast<Resolver *>(userdata);
if (err != kDNSServiceErr_NoError) { if (err != kDNSServiceErr_NoError) {
ref->cleanUp(ref->resolver); resolver->cleanUp();
return; return;
} }
@@ -155,28 +172,34 @@ void DNSSD_API QZeroConfPrivate::resolverCallback(DNSServiceRef, DNSServiceFlags
QByteArray avahiText((const char *)txtRecord, recLen); QByteArray avahiText((const char *)txtRecord, recLen);
QList<QByteArray> pair = avahiText.split('='); QList<QByteArray> pair = avahiText.split('=');
if (pair.size() == 2) if (pair.size() == 2)
ref->work.head()->m_txt[pair.at(0)] = pair.at(1); resolver->zcs->m_txt[pair.at(0)] = pair.at(1);
else else
ref->work.head()->m_txt[pair.at(0)] = ""; resolver->zcs->m_txt[pair.at(0)] = "";
txtLen-= recLen + 1; txtLen-= recLen + 1;
txtRecord+= recLen; txtRecord+= recLen;
} }
ref->work.head()->m_host = hostName; resolver->zcs->m_host = hostName;
ref->work.head()->m_port = qFromBigEndian<quint16>(port); resolver->zcs->m_port = qFromBigEndian<quint16>(port);
err = DNSServiceGetAddrInfo(&ref->resolver, kDNSServiceFlagsForceMulticast, interfaceIndex, ref->protocol, hostName, (DNSServiceGetAddrInfoReply) addressReply, ref);
if (resolver->DNSaddressRef) {
delete resolver->addressNotifier;
DNSServiceRefDeallocate(resolver->DNSaddressRef);
resolver->DNSaddressRef = nullptr;
}
err = DNSServiceGetAddrInfo(&resolver->DNSaddressRef, kDNSServiceFlagsForceMulticast, interfaceIndex, resolver->ref->protocol, hostName, (DNSServiceGetAddrInfoReply) addressReply, resolver);
if (err == kDNSServiceErr_NoError) { if (err == kDNSServiceErr_NoError) {
int sockfd = DNSServiceRefSockFD(ref->resolver); int sockfd = DNSServiceRefSockFD(resolver->DNSaddressRef);
if (sockfd == -1) { if (sockfd == -1) {
ref->cleanUp(ref->resolver); resolver->cleanUp();
} }
else { else {
ref->addressSocket = new QSocketNotifier(sockfd, QSocketNotifier::Read, ref); resolver->addressNotifier = new QSocketNotifier(sockfd, QSocketNotifier::Read);
connect(ref->addressSocket, SIGNAL(activated(int)), ref, SLOT(resolverRead())); connect(resolver->addressNotifier, &QSocketNotifier::activated, resolver, &Resolver::addressReady);
} }
} }
else { else {
ref->cleanUp(ref->resolver); resolver->cleanUp();
} }
} }
@@ -190,47 +213,31 @@ void DNSSD_API QZeroConfPrivate::addressReply(DNSServiceRef sdRef,
Q_UNUSED(ttl); Q_UNUSED(ttl);
Q_UNUSED(hostName); Q_UNUSED(hostName);
QZeroConfPrivate *ref = static_cast<QZeroConfPrivate *>(userdata); Resolver *resolver = static_cast<Resolver *>(userdata);
if (err == kDNSServiceErr_NoError) { if (err == kDNSServiceErr_NoError) {
if ((flags & kDNSServiceFlagsAdd) != 0) { if ((flags & kDNSServiceFlagsAdd) != 0) {
QHostAddress hAddress(address); QHostAddress hAddress(address);
ref->work.head()->setIp(hAddress); resolver->zcs->setIp(hAddress);
QString key = ref->work.head()->name() + QString::number(interfaceIndex); QString key = resolver->zcs->name() + QString::number(interfaceIndex);
if (!ref->pub->services.contains(key)) { if (!resolver->ref->pub->services.contains(key)) {
ref->pub->services.insert(key, ref->work.head()); resolver->ref->pub->services.insert(key, resolver->zcs);
emit ref->pub->serviceAdded(ref->work.head()); emit resolver->ref->pub->serviceAdded(resolver->zcs);
} }
else else
emit ref->pub->serviceUpdated(ref->work.head()); emit resolver->ref->pub->serviceUpdated(resolver->zcs);
} }
if (!(flags & kDNSServiceFlagsMoreComing))
ref->cleanUp(ref->resolver);
} }
else else
ref->cleanUp(ref->resolver); resolver->cleanUp();
} }
void QZeroConfPrivate::cleanUp(DNSServiceRef toClean) void QZeroConfPrivate::cleanUp(DNSServiceRef toClean)
{ {
if (!toClean) if (!toClean)
return; return;
if (toClean == resolver) {
if (addressSocket) {
delete addressSocket;
addressSocket = NULL;
}
if (resolverSocket) {
delete resolverSocket;
resolverSocket = NULL;
}
if(!work.isEmpty())
work.dequeue();
if (work.size())
resolve();
}
else if (toClean == browser) { else if (toClean == browser) {
browser = NULL; browser = NULL;
if (browserSocket) { if (browserSocket) {
@@ -239,6 +246,8 @@ void QZeroConfPrivate::cleanUp(DNSServiceRef toClean)
} }
QMap<QString, QZeroConfService >::iterator i; QMap<QString, QZeroConfService >::iterator i;
for (i = pub->services.begin(); i != pub->services.end(); i++) { for (i = pub->services.begin(); i != pub->services.end(); i++) {
QString key = (*i)->name() + QString::number((*i)->interfaceIndex());
resolvers[key]->cleanUp();
emit pub->serviceRemoved(*i); emit pub->serviceRemoved(*i);
} }
pub->services.clear(); pub->services.clear();
@@ -264,7 +273,6 @@ QZeroConf::~QZeroConf()
{ {
pri->cleanUp(pri->dnssRef); pri->cleanUp(pri->dnssRef);
pri->cleanUp(pri->browser); pri->cleanUp(pri->browser);
pri->cleanUp(pri->resolver);
delete pri; delete pri;
} }

View File

@@ -31,7 +31,6 @@
#include <QSocketNotifier> #include <QSocketNotifier>
#include <QtEndian> #include <QtEndian>
#include <QHostAddress> #include <QHostAddress>
#include <QQueue>
#include "qzeroconf.h" #include "qzeroconf.h"
#include <QDebug> #include <QDebug>
@@ -39,6 +38,23 @@
#define kDNSServiceFlagsTimeout 0x10000 #define kDNSServiceFlagsTimeout 0x10000
#endif #endif
class Resolver : public QObject
{
Q_OBJECT
public:
void cleanUp();
QZeroConfService zcs;
QZeroConfPrivate *ref = nullptr;
DNSServiceRef DNSresolverRef = nullptr;
DNSServiceRef DNSaddressRef = nullptr;
QSocketNotifier *resolverNotifier = nullptr;
QSocketNotifier *addressNotifier = nullptr;
public slots:
void resolverReady();
void addressReady();
};
class QZeroConfPrivate : public QObject class QZeroConfPrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -46,7 +62,7 @@ class QZeroConfPrivate : public QObject
public: public:
QZeroConfPrivate(QZeroConf *parent); QZeroConfPrivate(QZeroConf *parent);
void cleanUp(DNSServiceRef ref); void cleanUp(DNSServiceRef ref);
void resolve(void); void resolve(QZeroConfService);
static void DNSSD_API registerCallback(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *, static void DNSSD_API registerCallback(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *,
const char *, const char *, void *userdata); const char *, const char *, void *userdata);
@@ -61,16 +77,15 @@ public:
DNSServiceErrorType err, const char *hostName, const struct sockaddr* address, quint32 ttl, void *userdata); DNSServiceErrorType err, const char *hostName, const struct sockaddr* address, quint32 ttl, void *userdata);
QZeroConf *pub; QZeroConf *pub;
DNSServiceRef dnssRef, browser, resolver; DNSServiceRef dnssRef, browser;
DNSServiceProtocol protocol; DNSServiceProtocol protocol;
QSocketNotifier *bs, *browserSocket, *resolverSocket, *addressSocket; QSocketNotifier *bs, *browserSocket;
QQueue<QZeroConfService> work;
QByteArray txt; QByteArray txt;
QHash<QString, Resolver*> resolvers;
public slots: public slots:
void bsRead(); void bsRead();
void browserRead(); void browserRead();
void resolverRead();
}; };
#endif // QZEROCONFPRIVATE_H_ #endif // QZEROCONFPRIVATE_H_