zeroconf: windows support, avahi improvements, less messages

* support windows without apple bonjour installed
* avahi with autorefresh
* less spurious updates (messages when nothing actually changes)
* quickly give up on connecting to daemon the first time
* added startedBrowsing signal

Change-Id: I8a29d94040fa6ffae318c98782120123093d6616
Reviewed-by: Jarek Kobus <jaroslaw.kobus@nokia.com>
This commit is contained in:
Fawzi Mohamed
2012-03-08 20:06:52 +01:00
parent f1b2100e34
commit a9e7e07b45
10 changed files with 6451 additions and 88 deletions

View File

@@ -52,6 +52,7 @@
#include <avahi-common/error.h>
#include <netinet/in.h>
#include <sys/poll.h>
namespace ZeroConf {
namespace Internal {
@@ -70,6 +71,7 @@ extern "C" void cAvahiBrowseReply(
AvahiServiceBrowser * /*b*/, AvahiIfIndex interface, AvahiProtocol /*protocol*/,
AvahiBrowserEvent event, const char *name, const char *type, const char *domain,
AvahiLookupResultFlags /*flags*/, void* context);
extern "C" int cAvahiPollFunction(struct pollfd *ufds, unsigned int nfds, int timeout, void *userdata);
extern "C" {
typedef const AvahiPoll* (*AvahiSimplePollGet)(AvahiSimplePoll *s);
@@ -77,6 +79,7 @@ typedef AvahiSimplePoll *(*AvahiSimplePollNewPtr)(void);
typedef int (*AvahiSimplePollIteratePtr)(AvahiSimplePoll *s, int sleep_time);
typedef void (*AvahiSimplePollQuitPtr)(AvahiSimplePoll *s);
typedef void (*AvahiSimplePollFreePtr)(AvahiSimplePoll *s);
typedef void (*AvahiSimplePollSetFuncPtr)(AvahiSimplePoll *s, AvahiPollFunc func, void *userdata);
typedef AvahiClient* (*AvahiClientNewPtr)(
const AvahiPoll *poll_api, AvahiClientFlags flags, AvahiClientCallback callback,
void *userdata, int *error);
@@ -113,6 +116,7 @@ private:
AvahiSimplePollIteratePtr m_simplePollIterate;
AvahiSimplePollQuitPtr m_simplePollQuit;
AvahiSimplePollFreePtr m_simplePollFree;
AvahiSimplePollSetFuncPtr m_simplePollSetFunc;
AvahiClientNewPtr m_clientNew;
AvahiClientFreePtr m_clientFree;
AvahiServiceBrowserNewPtr m_serviceBrowserNew;
@@ -137,6 +141,7 @@ public:
m_simplePollIterate = reinterpret_cast<AvahiSimplePollIteratePtr>(nativeLib.resolve("avahi_simple_poll_iterate"));
m_simplePollQuit = reinterpret_cast<AvahiSimplePollQuitPtr>(nativeLib.resolve("avahi_simple_poll_quit"));
m_simplePollFree = reinterpret_cast<AvahiSimplePollFreePtr>(nativeLib.resolve("avahi_simple_poll_free"));
m_simplePollSetFunc = reinterpret_cast<AvahiSimplePollSetFuncPtr>(nativeLib.resolve("avahi_simple_poll_set_func"));
m_clientNew = reinterpret_cast<AvahiClientNewPtr>(nativeLib.resolve("avahi_client_new"));
m_clientFree = reinterpret_cast<AvahiClientFreePtr>(nativeLib.resolve("avahi_client_free"));
m_serviceBrowserNew = reinterpret_cast<AvahiServiceBrowserNewPtr>(nativeLib.resolve("avahi_service_browser_new"));
@@ -149,6 +154,7 @@ public:
m_simplePollIterate = reinterpret_cast<AvahiSimplePollIteratePtr>(&avahi_simple_poll_iterate);
m_simplePollQuit = reinterpret_cast<AvahiSimplePollQuitPtr>(&avahi_simple_poll_quit);
m_simplePollFree = reinterpret_cast<AvahiSimplePollFreePtr>(&avahi_simple_poll_free);
m_simplePollSetFunc = reinterpret_cast<AvahiSimplePollSetFuncPtr>(&avahi_simple_poll_set_func);
m_clientNew = reinterpret_cast<AvahiClientNewPtr>(&avahi_client_new);
m_clientFree = reinterpret_cast<AvahiClientFreePtr>(&avahi_client_free);
m_serviceBrowserNew = reinterpret_cast<AvahiServiceBrowserNewPtr>(&avahi_service_browser_new);
@@ -162,6 +168,7 @@ public:
if (!m_simplePollIterate) qDebug() << name() << " has null m_simplePollIterate";
if (!m_simplePollQuit) qDebug() << name() << " has null m_simplePollQuit";
if (!m_simplePollFree) qDebug() << name() << " has null m_simplePollFree";
if (!m_simplePollSetFunc) qDebug() << name() << " has null m_simplePollSetFunc";
if (!m_clientNew) qDebug() << name() << " has null m_clientNew";
if (!m_clientFree) qDebug() << name() << " has null m_clientFree";
if (!m_serviceBrowserNew) qDebug() << name() << " has null m_serviceBrowserNew";
@@ -286,6 +293,7 @@ public:
return kDNSServiceErr_Unknown;
//avahi_strerror(avahi_client_errno(client));
}
browser->activateAutoRefresh();
return kDNSServiceErr_NoError;
}
@@ -297,7 +305,7 @@ public:
return 0;
}
RunLoopStatus processOneEvent(ConnectionRef cRef, qint64 maxLockMs) {
RunLoopStatus processOneEvent(MainConnection *, ConnectionRef cRef, qint64 maxLockMs) {
if (!m_simplePollIterate)
return ProcessedFailure;
MyAvahiConnection *connection = reinterpret_cast<MyAvahiConnection *>(cRef);
@@ -309,11 +317,11 @@ public:
}
RunLoopStatus processOneEventBlock(ConnectionRef cRef) {
return processOneEvent(cRef,-1);
return processOneEvent(NULL,cRef,-1);
}
DNSServiceErrorType createConnection(ConnectionRef *sdRef) {
if (!m_simplePollNew || !m_clientNew)
DNSServiceErrorType createConnection(MainConnection *mainConnection, ConnectionRef *sdRef) {
if (!m_simplePollNew || !m_clientNew || !m_simplePollSetFunc)
return kDNSServiceErr_Unknown;
MyAvahiConnection *connection = new MyAvahiConnection;
connection->lib = this;
@@ -327,6 +335,8 @@ public:
delete connection;
return kDNSServiceErr_Unknown;
}
typedef void (*AvahiSimplePollSetFuncPtr)(AvahiSimplePoll *s, AvahiPollFunc func, void *userdata);
m_simplePollSetFunc(connection->simple_poll, &cAvahiPollFunction, mainConnection);
/* Allocate a new client */
int error;
connection->client = m_clientNew(m_simplePollGet(connection->simple_poll),
@@ -525,6 +535,20 @@ extern "C" void cAvahiBrowseReply(
}
}
extern "C" int cAvahiPollFunction(struct pollfd *ufds, unsigned int nfds, int timeout, void *userdata)
{
MainConnection *mainConnection = static_cast<MainConnection *>(userdata);
QMutex *lock = 0;
if (mainConnection)
lock = mainConnection->mainThreadLock();
if (lock)
lock->unlock();
int res=poll(ufds,nfds,timeout);
if (lock)
lock->lock();
return res;
}
} // namespace Internal
} // namespace ZeroConf

View File

@@ -138,6 +138,10 @@ public:
m_createConnection = reinterpret_cast<CreateConnectionPtr>(&DNSServiceCreateConnection);
m_refSockFD = reinterpret_cast<RefSockFDPtr>(&DNSServiceRefSockFD);
#endif
if (m_isOk && m_getAddrInfo == 0) {
m_isOk = false;
m_errorMsg = tr("*WARNING* DnsSdZConfLib detected an obsolete version of Apple Bonjour, either disable/uninstall it or upgrade it. Otherwise zeroconf will fail.");
}
if (DEBUG_ZEROCONF){
if (m_refDeallocate == 0) qDebug() << QLatin1String("DnsSdZConfLib.m_refDeallocate == 0");
if (m_resolve == 0) qDebug() << QLatin1String("DnsSdZConfLib.m_resolve == 0");
@@ -284,7 +288,7 @@ public:
return ProcessedOk;
}
DNSServiceErrorType createConnection(ConnectionRef *sdRef)
DNSServiceErrorType createConnection(MainConnection *, ConnectionRef *sdRef)
{
if (m_createConnection == 0) return kDNSServiceErr_Unsupported;
return m_createConnection(reinterpret_cast<DNSServiceRef *>(sdRef));
@@ -299,7 +303,6 @@ public:
ZConfLib::Ptr ZConfLib::createDnsSdLib(const QString &libName, ZConfLib::Ptr fallback) {
return ZConfLib::Ptr(new DnsSdZConfLib(libName, fallback));
return fallback;
}
} // namespace Internal
} // namespace ZeroConf

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -40,12 +40,11 @@ namespace ZeroConf { namespace embeddedLib {
static int gDaemonErr = kDNSServiceErr_NoError;
}}
extern "C" {
#if defined(_WIN32)
#define _SSIZE_T
#include <CommonServices.h>
#include <DebugServices.h>
#include "embed/CommonServices.h"
#include "embed/DebugServices.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
@@ -61,7 +60,7 @@ extern "C" {
// Disable warning: "nonstandard extension, function/data pointer conversion in expression"
#pragma warning(disable:4152)
extern BOOL IsSystemServiceDisabled();
//extern BOOL IsSystemServiceDisabled();
#define sleep(X) Sleep((X) * 1000)
#define NOT_HAVE_SA_LEN
@@ -83,6 +82,7 @@ namespace ZeroConf { namespace embeddedLib {
if ( buffer ) { vsprintf( buffer, message, args ); OutputDebugStringA( buffer ); free( buffer ); }
WSASetLastError( err );
}
}}
#else
#include <sys/fcntl.h> // For O_RDWR etc.
@@ -112,6 +112,7 @@ namespace ZeroConf { namespace embeddedLib {
#define CTL_PATH_PREFIX "/var/tmp/dnssd_result_socket."
#endif
extern "C" {
typedef struct
{
ipc_msg_hdr ipc_hdr;
@@ -427,6 +428,7 @@ static void FreeDNSServiceOp(DNSServiceOp *x)
// Return a connected service ref (deallocate with DNSServiceRefDeallocate)
static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags flags, uint32_t op, ProcessReplyFn ProcessReply, void *AppCallback, void *AppContext)
{
static int quickCheck = 1;
#if APPLE_OSX_mDNSResponder
int NumTries = DNSSD_CLIENT_MAXTRIES;
#else
@@ -462,7 +464,7 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { *ref = NULL; return kDNSServiceErr_ServiceNotRunning; }
}
// <rdar://problem/4096913> If the system service is disabled, we only want to try to connect once
if (IsSystemServiceDisabled()) NumTries = DNSSD_CLIENT_MAXTRIES;
//if (IsSystemServiceDisabled()) NumTries = DNSSD_CLIENT_MAXTRIES;
#endif
sdr = static_cast<DNSServiceOp*>(malloc(sizeof(DNSServiceOp)));
@@ -543,8 +545,10 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f
// daemon is still coming up. Rather than fail here, we'll wait a bit and try again.
// If, after four seconds, we still can't connect to the daemon,
// then we give up and return a failure code.
if (++NumTries < DNSSD_CLIENT_MAXTRIES) sleep(1); // Sleep a bit, then try again
else { dnssd_close(sdr->sockfd); FreeDNSServiceOp(sdr); return kDNSServiceErr_ServiceNotRunning; }
if (++NumTries < DNSSD_CLIENT_MAXTRIES && !quickCheck) sleep(1); // Sleep a bit, then try again
else {
quickCheck = 0;
dnssd_close(sdr->sockfd); FreeDNSServiceOp(sdr); return kDNSServiceErr_ServiceNotRunning; }
}
//printf("ConnectToServer opened socket %d\n", sdr->sockfd);
}

View File

@@ -44,6 +44,10 @@
#define EMBEDDED_LIB
#endif
#ifdef Q_OS_WIN32
#define EMBEDDED_LIB
#endif
#ifdef EMBEDDED_LIB
#include "embed/dnssd_ipc.c"
#include "embed/dnssd_clientlib.c"
@@ -204,7 +208,7 @@ public:
return ProcessedOk;
}
DNSServiceErrorType createConnection(ConnectionRef *sdRef)
DNSServiceErrorType createConnection(MainConnection *, ConnectionRef *sdRef)
{
return embeddedLib::DNSServiceCreateConnection(reinterpret_cast<DNSServiceRef*>(sdRef));
}

View File

@@ -135,16 +135,26 @@ public:
const QString &dnsSdDaemonPath);
private:
static const char *defaultmDnsSdLibName;
static const char *defaultmDNSDaemonName;
QMutex m_lock;
ZConfLib::Ptr m_defaultLib;
};
Q_GLOBAL_STATIC(ZeroConfLib, zeroConfLibInstance)
#ifdef Q_OS_WIN
const char *ZeroConfLib::defaultmDnsSdLibName = "dnssd";
const char *ZeroConfLib::defaultmDNSDaemonName = "mdnssd.exe";
#else
const char *ZeroConfLib::defaultmDnsSdLibName = "dns_sd";
const char *ZeroConfLib::defaultmDNSDaemonName = "mdnssd";
#endif
ZeroConfLib::ZeroConfLib(): m_lock(QMutex::Recursive),
m_defaultLib(ZConfLib::createAvahiLib(QLatin1String("avahi-client"),
ZConfLib::createDnsSdLib(QLatin1String("dns_sd"),
ZConfLib::createEmbeddedLib(QLatin1String("mdnssd")))))
ZConfLib::createDnsSdLib(QLatin1String(defaultmDnsSdLibName),
ZConfLib::createEmbeddedLib(QLatin1String(defaultmDNSDaemonName)))))
{
qRegisterMetaType<ZeroConf::Service::ConstPtr>("ZeroConf::Service::ConstPtr");
qRegisterMetaType<ZeroConf::ErrorMessage::SeverityLevel>("ZeroConf::ErrorMessage::SeverityLevel");
@@ -259,7 +269,24 @@ Service::~Service()
delete m_host;
}
ZEROCONFSHARED_EXPORT QDebug operator<<(QDebug dbg, const Service &service)
bool Service::operator==(const Service &o) const {
bool eq = m_fullName == o.m_fullName
&& m_name == o.m_name && m_type == o.m_type
&& m_domain == o.m_domain && m_port == o.m_port
&& m_txtRecord == o.m_txtRecord && m_interfaceNr == o.m_interfaceNr
&& m_outdated == m_outdated;
if (eq) {
if (m_host != o.m_host) {
if (m_host == 0 || o.m_host == 0)
return false;
return m_host->hostName() == o.m_host->hostName()
&& m_host->addresses() == o.m_host->addresses();
}
}
return eq;
}
QDebug operator<<(QDebug dbg, const Service &service)
{
dbg.maybeSpace() << "Service{ name:" << service.name() << ", "
<< "type:" << service.type() << ", domain:" << service.domain() << ", "
@@ -293,6 +320,16 @@ ZEROCONFSHARED_EXPORT QDebug operator<<(QDebug dbg, const Service &service)
dbg << " interfaceNr:" << service.interfaceNr() << ", outdated:" << service.outdated() << " }";
return dbg.space();
}
QDebug operator<<(QDebug dbg, const Service::ConstPtr &service){
if (service.data() == 0){
dbg << "Service{*NULL*}";
} else {
dbg << *service.data();
}
return dbg;
}
// inline methods
/*!
\fn bool Service::outdated() const
@@ -369,16 +406,17 @@ void ServiceBrowser::startBrowsing(qint32 interfaceIndex)
/// create a new brower for the given service type
ServiceBrowser::ServiceBrowser(const QString &serviceType, const QString &domain,
AddressesSetting addressesSetting, QObject *parent)
: QObject(parent),
: QObject(parent), timer(0),
d(new ServiceBrowserPrivate(serviceType, domain, addressesSetting == RequireAddresses,
MainConnectionPtr()))
{
connect(this,SIGNAL(activateAutoRefresh()),this,SLOT(autoRefresh()));
d->q = this;
}
ServiceBrowser::ServiceBrowser(const MainConnectionPtr &mainConnection, const QString &serviceType,
const QString &domain, AddressesSetting addressesSetting, QObject *parent)
: QObject(parent),
: QObject(parent), timer(0),
d(new ServiceBrowserPrivate(serviceType, domain, addressesSetting == RequireAddresses,
mainConnection))
{
@@ -399,6 +437,11 @@ MainConnectionPtr ServiceBrowser::mainConnection() const
/// stops browsing, but does not delete all services found
void ServiceBrowser::stopBrowsing()
{
if (timer) {
timer->stop();
delete timer;
timer = 0;
}
d->stopBrowsing();
}
@@ -452,6 +495,16 @@ void ServiceBrowser::reconfirmService(Service::ConstPtr service)
d->reconfirmService(service);
}
void ServiceBrowser::autoRefresh()
{
QMutexLocker l(d->mainConnection->lock());
if (!timer) {
timer = new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(triggerRefresh()));
timer->start(5000);
}
}
// signals
/*!
\fn void ServiceBrowser::serviceChanged(
@@ -485,6 +538,24 @@ void ServiceBrowser::reconfirmService(Service::ConstPtr service)
services(), use this signal, not serviceChanged(), serviceAdded() or serviceRemoved() to know
about changes to the list.
*/
/*!
\fn void errorMessage(ZeroConf::ErrorMessage::SeverityLevel severity, const QString &msg, ZeroConf::ServiceBrowser *browser)
This signal is called every time a warning or error is emitted (for example when a library
cannot be used and another one has to be used). Zeroconf will still work if severity < FailureLevel.
*/
/*!
\fn void hadFailure(const QList<ZeroConf::ErrorMessage> &messages, ZeroConf::ServiceBrowser *browser)
This signal is emitted only when a full failure has happened, and all the previous errors/attempts to set up zeroconf
are passed in messages.
*/
/*!
\fn void startedBrowsing(ZeroConf::ServiceBrowser *browser)
This signal is emitted when browsing has actually started.
One can rely on either startedBrowsing or hadFailure to be emitted.
*/
// ----------------- library initialization impl -----------------
/*!
@@ -631,25 +702,32 @@ QString ServiceGatherer::fullName(){
return currentService->fullName();
}
void ServiceGatherer::enactServiceChange()
bool ServiceGatherer::enactServiceChange()
{
if (DEBUG_ZEROCONF)
qDebug() << "ServiceGatherer::enactServiceChange() for service "
<< currentService->fullName();
if (currentServiceCanBePublished()) {
if ((publishedService.data() == 0 && currentService == 0)
|| (publishedService.data() != 0 && currentService != 0
&& *publishedService == *currentService))
return false;
Service::Ptr nService = Service::Ptr(currentService);
serviceBrowser->serviceChanged(publishedService, nService, serviceBrowser->q);
if (publishedService) {
publishedService->invalidate();
serviceBrowser->nextActiveServices.removeOne(publishedService);
serviceBrowser->serviceRemoved(publishedService, serviceBrowser->q);
}
serviceBrowser->serviceChanged(publishedService, nService, serviceBrowser->q);
publishedService = nService;
if (nService) {
serviceBrowser->nextActiveServices.append(nService);
serviceBrowser->serviceAdded(nService, serviceBrowser->q);
currentService = new Service(*currentService);
}
return true;
}
return false;
}
void ServiceGatherer::retireService()
@@ -660,8 +738,9 @@ void ServiceGatherer::retireService()
<< currentService->fullName();
Service::Ptr nService;
serviceBrowser->nextActiveServices.removeOne(publishedService);
serviceBrowser->serviceChanged(publishedService, nService, serviceBrowser->q);
publishedService->invalidate();
serviceBrowser->serviceRemoved(publishedService, serviceBrowser->q);
serviceBrowser->serviceChanged(publishedService, nService, serviceBrowser->q);
publishedService = nService;
} else if (DEBUG_ZEROCONF){
qDebug() << "ServiceGatherer::retireService() for non published service "
@@ -897,7 +976,6 @@ void ServiceGatherer::serviceResolveReply(DNSServiceFlags fl
}
return;
}
if (publishedService) publishedService->invalidate(); // delay this to enactServiceChange?
serviceBrowser->updateFlowStatusForFlags(flags);
uint16_t nKeys = txtRecordGetCount(txtLen, rawTxtRecord);
for (uint16_t i = 0; i < nKeys; ++i){
@@ -1041,7 +1119,7 @@ void ServiceGatherer::addrReply(DNSServiceFlags flags,
const struct sockaddr *address,
uint32_t /*ttl*/) // should we use this???
{
if (errorCode != kDNSServiceErr_NoError){
if (errorCode != kDNSServiceErr_NoError) {
if (errorCode == kDNSServiceErr_Timeout){
if ((status & AddrConnectionSuccess) == 0){
qDebug() << "ServiceBrowser " << serviceBrowser->serviceType
@@ -1088,8 +1166,12 @@ void ServiceGatherer::addrReply(DNSServiceFlags flags,
} else {
if (!addrNow.contains(newAddr)){
switch (newAddr.protocol()){
case QAbstractSocket::IPv6Protocol:
addrNow.insert(0, newAddr); // prefers IPv6 addresses
#ifdef Q_OS_WIN
case QAbstractSocket::IPv4Protocol: // prefers IPv4 addresses
#else
case QAbstractSocket::IPv6Protocol: // prefers IPv6 addresses
#endif
addrNow.insert(0, newAddr);
break;
default:
addrNow.append(newAddr);
@@ -1239,6 +1321,7 @@ void ServiceBrowserPrivate::maybeUpdateLists()
qint64 now = QDateTime::currentMSecsSinceEpoch();
QList<QString>::iterator i = knownServices.begin(), endi = knownServices.end();
QMap<QString, ServiceGatherer::Ptr>::iterator j = gatherers.begin();
bool hasServicesChanges = false;
while (i != endi && j != gatherers.end()) {
const QString vi = *i;
QString vj = j.value()->fullName();
@@ -1253,6 +1336,7 @@ void ServiceBrowserPrivate::maybeUpdateLists()
pendingGatherers.removeAll(j.value());
j.value()->retireService();
j = gatherers.erase(j);
hasServicesChanges = true;
} else {
++j;
}
@@ -1266,18 +1350,21 @@ void ServiceBrowserPrivate::maybeUpdateLists()
pendingGatherers.removeAll(j.value());
j.value()->retireService();
j = gatherers.erase(j);
hasServicesChanges = true;
} else {
++j;
}
}
foreach (const ServiceGatherer::Ptr &g, pendingGatherers)
g->enactServiceChange();
hasServicesChanges = hasServicesChanges || g->enactServiceChange();
if (hasServicesChanges) {
{
QMutexLocker l(mainConnection->lock());
activeServices = nextActiveServices;
}
emit q->servicesUpdated(q);
}
}
if (shouldRefresh)
refresh();
}
@@ -1333,6 +1420,11 @@ void ServiceBrowserPrivate::browseReply(DNSServiceFlags flag
maybeUpdateLists(); // avoid?
}
void ServiceBrowserPrivate::activateAutoRefresh()
{
emit q->activateAutoRefresh();
}
void ServiceBrowserPrivate::startBrowsing(quint32 interfaceIndex)
{
this->interfaceIndex = interfaceIndex;
@@ -1364,11 +1456,18 @@ bool ServiceBrowserPrivate::internalStartBrowsing()
void ServiceBrowserPrivate::triggerRefresh()
{
{
QMutexLocker l(mainConnection->lock());
const qint64 msecDelay = 5100;
delayDeletesUntil = QDateTime::currentMSecsSinceEpoch() + msecDelay;
stopBrowsing();
shouldRefresh = true;
}
{
QMutexLocker l(mainConnection->mainThreadLock());
if (!browsing)
refresh();
}
}
void ServiceBrowserPrivate::refresh()
@@ -1444,6 +1543,11 @@ void ServiceBrowserPrivate::hadFailure(const QList<ErrorMessage> &messages)
emit q->hadFailure(messages, q);
}
void ServiceBrowserPrivate::startedBrowsing()
{
emit q->startedBrowsing(q);
}
// ----------------- MainConnection impl -----------------
void MainConnection::stop(bool wait)
@@ -1463,8 +1567,8 @@ void MainConnection::stop(bool wait)
}
MainConnection::MainConnection():
lib(zeroConfLibInstance()->defaultLib()), m_lock(QMutex::Recursive), m_mainRef(0),
m_failed(false), m_status(Starting), m_nErrs(0)
lib(zeroConfLibInstance()->defaultLib()), m_lock(QMutex::Recursive),
m_mainThreadLock(QMutex::Recursive), m_mainRef(0), m_failed(false), m_status(Starting), m_nErrs(0)
{
if (lib.isNull()){
qDebug() << "could not load a valid library for ZeroConf::MainConnection, failing";
@@ -1505,6 +1609,11 @@ QMutex *MainConnection::lock()
return &m_lock;
}
QMutex *MainConnection::mainThreadLock()
{
return &m_mainThreadLock;
}
void MainConnection::waitStartup()
{
int sAtt;
@@ -1537,9 +1646,8 @@ void MainConnection::addBrowser(ServiceBrowserPrivate *browser)
m_browsers.append(browser);
errs = m_errors;
}
if (actualStatus == Running) {
browser->internalStartBrowsing();
}
if (actualStatus == Running && browser->internalStartBrowsing())
browser->startedBrowsing();
bool didFail = false;
foreach (const ErrorMessage &msg, errs) {
browser->errorMessage(msg.severity, msg.msg);
@@ -1620,7 +1728,7 @@ void MainConnection::createConnection()
uint32_t size = (uint32_t)sizeof(uint32_t);
DNSServiceErrorType err = lib->getProperty(kDNSServiceProperty_DaemonVersion, &version, &size);
if (err == kDNSServiceErr_NoError){
DNSServiceErrorType error = lib->createConnection(&m_mainRef);
DNSServiceErrorType error = lib->createConnection(this, &m_mainRef);
if (error != kDNSServiceErr_NoError){
appendError(ErrorMessage::WarningLevel, tr("MainConnection using lib %1 failed the initialization of mainRef with error %2")
.arg(lib->name()).arg(error));
@@ -1636,8 +1744,9 @@ void MainConnection::createConnection()
}
for (int i = waitingBrowsers.count(); i-- != 0; ){
ServiceBrowserPrivate *actualBrowser = waitingBrowsers[i];
if (actualBrowser && !actualBrowser->browsing)
actualBrowser->internalStartBrowsing();
if (actualBrowser && !actualBrowser->browsing
&& actualBrowser->internalStartBrowsing())
actualBrowser->startedBrowsing();
}
break;
}
@@ -1672,11 +1781,11 @@ ZConfLib::RunLoopStatus MainConnection::handleEvent()
nextEvent = bAtt->delayDeletesUntil;
}
if (nextEvent <= now)
nextEvent = 5000;
nextEvent = -1;
else
nextEvent -= now;
maybeUpdateLists();
ZConfLib::RunLoopStatus err = lib->processOneEvent(m_mainRef, nextEvent);
ZConfLib::RunLoopStatus err = lib->processOneEvent(this, m_mainRef, nextEvent);
if (err != ZConfLib::ProcessedOk && err != ZConfLib::ProcessedIdle) {
qDebug() << "processOneEvent returned " << err;
++m_nErrs;
@@ -1715,6 +1824,7 @@ void MainConnection::handleEvents()
#else
while (m_status < Stopping) {
#endif
QMutexLocker l(mainThreadLock());
if (m_nErrs > 10)
increaseStatusTo(Stopping);
switch (handleEvent()) {
@@ -1821,11 +1931,12 @@ void ZConfLib::setError(bool failure, const QString &eMsg)
m_isOk = !failure;
}
ZConfLib::RunLoopStatus ZConfLib::processOneEvent(ConnectionRef cRef, qint64 maxMsBlock)
ZConfLib::RunLoopStatus ZConfLib::processOneEvent(MainConnection *mainConnection,
ConnectionRef cRef, qint64 maxMsBlock)
{
if (maxMsBlock < 0) { // just block
return processOneEventBlock(cRef);
} else {
maxMsBlock = MAX_SEC_FOR_READ * static_cast<qint64>(1000);
}
// some stuff could be extracted for maximal performance
int dns_sd_fd = (cRef ? refSockFD(cRef) : -1);
int nfds = dns_sd_fd + 1;
@@ -1846,7 +1957,12 @@ ZConfLib::RunLoopStatus ZConfLib::processOneEvent(ConnectionRef cRef, qint64 max
tv.tv_sec = static_cast<time_t>(maxMsBlock / 1000);
tv.tv_usec = static_cast<suseconds_t>((maxMsBlock % 1000) * 1000);
}
QMutex *lock = (mainConnection ? mainConnection->mainThreadLock() : 0);
if (lock)
lock->unlock();
result = select(nfds, &readfds, (fd_set *)NULL, (fd_set *)NULL, &tv);
if (lock)
lock->lock();
if (result > 0) {
if (FD_ISSET(dns_sd_fd, &readfds))
return processOneEventBlock(cRef);
@@ -1859,7 +1975,6 @@ ZConfLib::RunLoopStatus ZConfLib::processOneEvent(ConnectionRef cRef, qint64 max
return ProcessedError;
}
return ProcessedIdle; // change? should never happen anyway
}
}
} // namespace Internal

View File

@@ -39,6 +39,7 @@
#include <QObject>
#include <QSharedPointer>
#include <QStringList>
#include <QTimer>
QT_FORWARD_DECLARE_CLASS(QHostInfo)
@@ -99,6 +100,7 @@ public:
const ServiceTxtRecord &txtRecord() const { return m_txtRecord; }
const QHostInfo *host() const { return m_host; }
int interfaceNr() const { return m_interfaceNr; }
bool operator==(const Service &o) const;
bool invalidate() { bool res = m_outdated; m_outdated = true; return res; }
private:
@@ -114,6 +116,7 @@ private:
};
ZEROCONFSHARED_EXPORT QDebug operator<<(QDebug dbg, const Service &service);
ZEROCONFSHARED_EXPORT QDebug operator<<(QDebug dbg, const Service::ConstPtr &service);
class ZEROCONFSHARED_EXPORT ServiceBrowser : public QObject
{
@@ -133,7 +136,6 @@ public:
void startBrowsing(qint32 interfaceIndex = 0);
void stopBrowsing();
void triggerRefresh();
bool isBrowsing() const;
bool didFail() const;
@@ -145,7 +147,11 @@ public:
QList<Service::ConstPtr> services() const;
void reconfirmService(Service::ConstPtr service);
public slots:
void triggerRefresh();
void autoRefresh();
signals:
void activateAutoRefresh();
void serviceChanged(const ZeroConf::Service::ConstPtr &oldService,
const ZeroConf::Service::ConstPtr &newService, ZeroConf::ServiceBrowser *browser);
void serviceAdded(const ZeroConf::Service::ConstPtr &service,
@@ -155,7 +161,9 @@ signals:
void servicesUpdated(ZeroConf::ServiceBrowser *browser);
void errorMessage(ZeroConf::ErrorMessage::SeverityLevel severity, const QString &msg, ZeroConf::ServiceBrowser *browser);
void hadFailure(const QList<ZeroConf::ErrorMessage> &messages, ZeroConf::ServiceBrowser *browser);
void startedBrowsing(ZeroConf::ServiceBrowser *browser);
private:
QTimer *timer;
Internal::ServiceBrowserPrivate *d;
};

View File

@@ -109,8 +109,10 @@ public:
ServiceBrowserPrivate *browser) = 0;
virtual DNSServiceErrorType getProperty(const char *property, void *result, uint32_t *size) = 0;
virtual RunLoopStatus processOneEventBlock(ConnectionRef sdRef) = 0;
virtual RunLoopStatus processOneEvent(ConnectionRef sdRef, qint64 maxMsBlock);
virtual DNSServiceErrorType createConnection(ConnectionRef *sdRef) = 0;
virtual RunLoopStatus processOneEvent(MainConnection *mainConnection,
ConnectionRef sdRef, qint64 maxMsBlock);
virtual DNSServiceErrorType createConnection(MainConnection *mainConnection,
ConnectionRef *sdRef) = 0;
virtual void stopConnection(ConnectionRef cRef) = 0;
virtual void destroyConnection(ConnectionRef *sdRef) = 0;
virtual int refSockFD(ConnectionRef sdRef) = 0;
@@ -154,7 +156,7 @@ public:
};
QString fullName();
void enactServiceChange();
bool enactServiceChange();
void retireService();
Ptr gatherer();
@@ -232,6 +234,7 @@ public:
MainConnection();
~MainConnection();
QMutex *lock();
QMutex *mainThreadLock();
void waitStartup();
void stop(bool wait = true);
void addBrowser(ServiceBrowserPrivate *browser);
@@ -253,7 +256,7 @@ public:
private:
void appendError(ErrorMessage::SeverityLevel severity, const QString &msg);
mutable QMutex m_lock;
mutable QMutex m_lock, m_mainThreadLock;
QList<ServiceBrowserPrivate *> m_browsers;
ZConfLib::ConnectionRef m_mainRef;
bool m_failed;
@@ -309,6 +312,7 @@ public:
uint32_t interfaceIndex, ZK_IP_Protocol proto, DNSServiceErrorType errorCode,
const char *serviceName, const char *regtype, const char *replyDomain);
void activateAutoRefresh();
void serviceChanged(const Service::ConstPtr &oldService, const Service::ConstPtr &newService,
ServiceBrowser *browser);
void serviceAdded(const Service::ConstPtr &service, ServiceBrowser *browser);
@@ -316,6 +320,7 @@ public:
void servicesUpdated(ServiceBrowser *browser);
void errorMessage(ErrorMessage::SeverityLevel severity, const QString &msg);
void hadFailure(const QList<ErrorMessage> &msgs);
void startedBrowsing();
};
class ConnectionThread: public QThread {