aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/zeroconf/servicebrowser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/zeroconf/servicebrowser.cpp')
-rw-r--r--src/libs/zeroconf/servicebrowser.cpp2103
1 files changed, 0 insertions, 2103 deletions
diff --git a/src/libs/zeroconf/servicebrowser.cpp b/src/libs/zeroconf/servicebrowser.cpp
deleted file mode 100644
index 1ec63e8cda1..00000000000
--- a/src/libs/zeroconf/servicebrowser.cpp
+++ /dev/null
@@ -1,2103 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://www.qt.io/licensing. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-#include "zeroconf_global.h"
-#ifdef Q_OS_WIN
-// Disable min max macros from windows headers,
-// because we want to use the template methods from std.
-# ifndef NOMINMAX
-# define NOMINMAX
-# endif
-# include <winsock2.h>
-#endif // Q_OS_WIN
-
-#include "mdnsderived.h"
-#include "servicebrowser_p.h"
-
-#include <algorithm>
-#include <errno.h>
-#include <limits>
-#include <signal.h>
-#ifdef Q_OS_UNIX
-// for select()
-# include <unistd.h>
-#endif
-
-#include <QAtomicPointer>
-#include <QCoreApplication>
-#include <QDateTime>
-#include <QGlobalStatic>
-#include <QMetaType>
-#include <QMutexLocker>
-#include <QNetworkInterface>
-#include <QString>
-#include <QStringList>
-#include <QtEndian>
-#include <QHostInfo>
-
-//the timeval struct under windows uses long instead of suseconds_t
-#ifdef Q_OS_WIN
-typedef long suseconds_t;
-#endif
-
-/*!
- \namespace ZeroConf
-
- \brief The ZeroConf namespace provides zeroconf (Bonjour/DNS-SD)
- functionality, currently mostly for browsing services.
-*/
-
-namespace { // anonymous namespace for free functions
-// ----------------- free functions -----------------
-
-using namespace ZeroConf;
-using namespace ZeroConf::Internal;
-
-QString toFullNameC(const char * const service, const char * const regtype, const char * const domain)
-{
- char fullName[kDNSServiceMaxDomainName];
- myDNSServiceConstructFullName(fullName, service, regtype, domain);
- fullName[kDNSServiceMaxDomainName - 1] = 0; // just to be sure
- return QString::fromUtf8(fullName);
-}
-
-int fromFullNameC(const char * const fullName, QString &service, QString &regtype, QString &domain)
-{
- char fullNameDecoded[kDNSServiceMaxDomainName];
- int encodedI = 0;
- int decodedI = 0;
- int oldPos[4];
- int iPos = 0;
- while (fullName[encodedI] != 0 && encodedI <kDNSServiceMaxDomainName){
- char c = fullName[encodedI++];
- if (c == '\\'){
- c = fullName[++encodedI];
- if (c == 0 || encodedI == kDNSServiceMaxDomainName)
- return 1;
- if (c >= '0' && c <= '9'){
- int val = (c - '0') * 100;
- c = fullName[++encodedI];
- if (c < '0' || c > '9' || encodedI == kDNSServiceMaxDomainName)
- return 2;
- val += (c - '0') * 10;
- c = fullName[++encodedI];
- if (c < '0' || c > '9')
- return 3;
- val += (c - '0');
- fullNameDecoded[decodedI++] = static_cast<char>(static_cast<unsigned char>(val));
- } else {
- fullNameDecoded[decodedI++] = c;
- }
- } else if (c == '.') {
- if (iPos < 4)
- oldPos[iPos++] = decodedI;
- fullNameDecoded[decodedI++] = c;
- } else {
- fullNameDecoded[decodedI++] = c;
- }
- }
- if (iPos != 4) return 5;
- service = QString::fromUtf8(&fullNameDecoded[0], oldPos[0]);
- regtype = QString::fromUtf8(&fullNameDecoded[oldPos[0] + 1], oldPos[3] - oldPos[0] - 1);
- domain = QString::fromUtf8(&fullNameDecoded[oldPos[3] + 1], decodedI - oldPos[3] - 1);
- return 0;
-}
-
-/// singleton for lib setup
-class ZeroConfLib
-{
-public:
- ZeroConfLib();
- ZConfLib::Ptr defaultLib();
- void setDefaultLib(LibUsage usage, const QString &avahiLibName, const QString &avahiVersion,
- const QString &dnsSdLibName, const QString &dnsSdDaemonPath);
- int nFallbacksTot() const;
-
-private:
- static const char *defaultmDnsSdLibName;
- static const char *defaultmDNSDaemonName;
- int m_nFallbacksTot;
- 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::createDnsSdLib(QLatin1String(defaultmDnsSdLibName),
- ZConfLib::createEmbeddedLib(QString(),
- ZConfLib::createAvahiLib(QLatin1String("avahi-client"),QLatin1String("3"),
- ZConfLib::createEmbeddedLib(QLatin1String(defaultmDNSDaemonName))))))
-{
- qRegisterMetaType<ZeroConf::Service::ConstPtr>("ZeroConf::Service::ConstPtr");
- qRegisterMetaType<ZeroConf::ErrorMessage::SeverityLevel>("ZeroConf::ErrorMessage::SeverityLevel");
- qRegisterMetaType<ZeroConf::ErrorMessage>("ZeroConf::ErrorMessage");
- qRegisterMetaType<QList<ZeroConf::ErrorMessage> >("QList<ZeroConf::ErrorMessage>");
- m_nFallbacksTot = (m_defaultLib ? m_defaultLib->nFallbacks() : 0);
-
-}
-
-ZConfLib::Ptr ZeroConfLib::defaultLib(){
- QMutexLocker l(&m_lock);
- return m_defaultLib;
-}
-
-void ZeroConfLib::setDefaultLib(LibUsage usage, const QString &avahiLibName,
- const QString &avahiVersion, const QString &dnsSdLibName,
- const QString &dnsSdDaemonPath){
- QMutexLocker l(&m_lock);
- switch (usage){
- case (UseDnsSdOnly):
- m_defaultLib = ZConfLib::createDnsSdLib(dnsSdLibName);
- break;
- case (UseEmbeddedOnly):
- m_defaultLib = ZConfLib::createEmbeddedLib(dnsSdDaemonPath);
- break;
- case (UseAvahiOnly):
- m_defaultLib = ZConfLib::createAvahiLib(avahiLibName, avahiVersion);
- break;
- case (UseAvahiOrDnsSd):
- m_defaultLib = ZConfLib::createAvahiLib(avahiLibName, avahiVersion,
- ZConfLib::createDnsSdLib(dnsSdLibName));
- break;
- case (UseAvahiOrDnsSdOrEmbedded):
- m_defaultLib = ZConfLib::createAvahiLib(avahiLibName, avahiVersion,
- ZConfLib::createDnsSdLib(dnsSdLibName,
- ZConfLib::createEmbeddedLib(dnsSdDaemonPath)));
- break;
- default:
- qDebug() << "invalid usage " << usage;
- }
- int newNFallbacks = m_defaultLib->nFallbacks();
- if (m_nFallbacksTot < newNFallbacks)
- m_nFallbacksTot = newNFallbacks;
-}
-
-int ZeroConfLib::nFallbacksTot() const
-{
- return m_nFallbacksTot;
-}
-
-} // end anonymous namespace
-
-namespace ZeroConf {
-
-int gQuickStop = 0;
-
-// ----------------- ErrorMessage impl -----------------
-/*!
- \class ZeroConf::ErrorMessage
-
- \brief The ErrorMessage class represents an error message.
-
- */
-
-/// empty constructor (required by qRegisterMetaType)
-ErrorMessage::ErrorMessage(): severity(FailureLevel) {}
-/// constructor
-ErrorMessage::ErrorMessage(SeverityLevel s, const QString &m): severity(s), msg(m) {}
-
-/// returns a human readable string for each severity level
-QString ErrorMessage::severityLevelToString(ErrorMessage::SeverityLevel severity)
-{
- const char *ctx = "Zeroconf::SeverityLevel";
- switch (severity) {
- case NoteLevel:
- return QCoreApplication::translate(ctx, "NOTE");
- case WarningLevel:
- return QCoreApplication::translate(ctx, "WARNING");
- case ErrorLevel:
- return QCoreApplication::translate(ctx, "ERROR");
- case FailureLevel:
- return QCoreApplication::translate(ctx, "FATAL_ERROR");
- default:
- return QCoreApplication::translate(ctx, "UNKNOWN_LEVEL_%1").arg(severity);
- }
-}
-
-QDebug operator<<(QDebug dbg, const ErrorMessage &eMsg)
-{
- dbg << ErrorMessage::severityLevelToString(eMsg.severity) << eMsg.msg;
- return dbg;
-}
-
-// ----------------- Service impl -----------------
-/*!
- \class ZeroConf::Service
-
- \brief The Service class represents a zeroconf service.
-
- Instances of this class are basically constant, but can be outdated. They are normally accessed
- through a Shared pointer.
- This design avoids race conditions when used though multiple threads.
-
- \threadsafe
- */
-
-Service::Service(const Service &o) :
- m_name(o.m_name),
- m_type(o.m_type),
- m_domain(o.m_domain),
- m_fullName(o.m_fullName),
- m_port(o.m_port),
- m_txtRecord(o.m_txtRecord),
- m_host(o.m_host ? new QHostInfo(*o.m_host) : 0),
- m_interfaceNr(o.m_interfaceNr),
- m_outdated(o.m_outdated)
-{
-}
-
-Service::Service() : m_host(0), m_interfaceNr(0), m_outdated(false)
-{ }
-
-Service::~Service()
-{
- delete m_host;
-}
-
-/*!
- Returns the interface on which the service is reachable.
- */
-QNetworkInterface Service::networkInterface() const
-{
- return QNetworkInterface::interfaceFromIndex(m_interfaceNr);
-}
-
-QStringList Service::addresses(Service::AddressStyle style) const
-{
- QStringList res;
- if (host() == 0)
- return res;
- foreach (const QHostAddress &addr, host()->addresses()){
- QString addrStr;
- if (addr.protocol() == QAbstractSocket::IPv6Protocol) {
- // Add the interface to use to the address <address>%<interface>
- //
- // This is required only for link local addresses (like fe80:*)
- // but as we have it we do it (and most likely addresses here are
- // link local).
- //
- // on windows only addresses like fe80::42%22 work
- // on OSX 10.5 only things like fe80::42%en4 work
- // on later OSX versions and linux both <address>%<interface number>
- // and <address>%<interface name> work, we use the interface name as
- // it looks better
-#ifdef Q_OS_WIN
- QString interfaceStr = QString::number(networkInterface().index());
-#else
- QString interfaceStr = networkInterface().name();
-#endif
- addrStr = QString::fromLatin1("%1%%2").arg(addr.toString()).arg(interfaceStr);
- if (style == QuoteIPv6Adresses)
- addrStr = QString::fromLatin1("[%1]").arg(addrStr);
- } else {
- addrStr = addr.toString();
- }
- res.append(addrStr);
- }
- return res;
-}
-
-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 == o.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() << ", "
- << " fullName:" << service.fullName() << ", port:" << service.port()
- << ", txtRecord:{";
- bool first = true;
- QHashIterator<QString, QString> i(service.txtRecord());
- while (i.hasNext()){
- i.next();
- if (first)
- first = false;
- else
- dbg << ", ";
- dbg << i.key() << ":" << i.value();
- }
- dbg << "}, ";
- if (const QHostInfo *host = service.host()){
- dbg << "host:{" << host->hostName() << ", addresses[";
- first = true;
- foreach (const QHostAddress &addr, host->addresses()){
- if (first)
- first = false;
- else
- dbg << ", ";
- dbg << addr.toString();
- }
- dbg << "], },";
- } else {
- dbg << " host:*null*,";
- }
- 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
-
- Returns whether the service data is outdated. Its value might change even on
- the (otherwise constant) objects returned by a ServiceBrowser.
-*/
-/*!
- \fn QString Service::name() const
-
- Returns the name of the service (non escaped).
-*/
-/*!
- \fn QString Service::type() const
-
- Returns the name of the service type (non escaped).
-*/
-/*!
- \fn QString Service::domain() const
-
- Returns the name of the domain (non escaped).
-*/
-/*!
- \fn QString Service::fullName() const
-
- Returns the full name (service.type.domain) with each component correctly escaped.
-*/
-/*!
- \fn QString Service::port() const
-
- Returns the port of the service (as a string, not as number).
-*/
-/*!
- \fn const Service::ServiceTxtRecord &txtRecord() const
-
- Returns the extra information on this service.
-*/
-/*!
- \fn const Service::QHostInfo *host() const
-
- Returns the host through which this service is reachable.
-*/
-/*!
- \fn int Service::interfaceNr() const
-
- Returns the interface on which the service is reachable, 1 based, 0 means to
- try all interfaces.
-*/
-/*!
- \fn bool Service::invalidate()
-
- Marks this service as outdated.
-*/
-
-// ----------------- ServiceBrowser impl -----------------
-/*!
- \class ZeroConf::ServiceBrowser
-
- \brief The ServiceBrowser class browses (searches) for a given zeronconf
- service.
-
- The actual browsing starts only when startBrowsing() is called. If you want to receive all service
- changes, connect before starting browsing.
-
- The current list of services can be gathered with the services() method.
-
- \threadsafe
- */
-
-/// starts the browsing, return true if successfull
-void ServiceBrowser::startBrowsing(qint32 interfaceIndex)
-{
- d->startBrowsing(interfaceIndex);
-}
-
-/// create a new brower for the given service type
-ServiceBrowser::ServiceBrowser(const QString &serviceType, const QString &domain,
- AddressesSetting addressesSetting, 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), timer(0),
- d(new ServiceBrowserPrivate(serviceType, domain, addressesSetting == RequireAddresses,
- mainConnection))
-{
- d->q = this;
-}
-
-ServiceBrowser::~ServiceBrowser()
-{
- delete d;
-}
-
-/// returns the main connection used by this ServiceBrowser
-MainConnectionPtr ServiceBrowser::mainConnection() const
-{
- return d->mainConnection;
-}
-
-/// stops browsing, but does not delete all services found
-void ServiceBrowser::stopBrowsing()
-{
- if (timer) {
- timer->stop();
- delete timer;
- timer = 0;
- }
- d->stopBrowsing();
-}
-
-/// starts an explicit browse (important especially with avahi)
-void ServiceBrowser::triggerRefresh()
-{
- d->triggerRefresh();
-}
-
-/// if the service is currently active
-bool ServiceBrowser::isBrowsing() const
-{
- return d->browsing;
-}
-
-/// type of the service browsed (non escaped)
-const QString& ServiceBrowser::serviceType() const
-{
- return d->serviceType;
-}
-
-/// domain that is browser (non escaped)
-const QString& ServiceBrowser::domain() const
-{
- return d->domain;
-}
-
-/// if addresses should be resolved automatically for each service found
-bool ServiceBrowser::adressesAutoResolved() const
-{
- return d->autoResolveAddresses;
-}
-
-/// if addresses are required to add the service to the list of available services
-bool ServiceBrowser::addressesRequired() const
-{
- return d->requireAddresses;
-}
-
-/// list of current services (by copy on purpose)
-QList<Service::ConstPtr> ServiceBrowser::services() const
-{
- QMutexLocker l(d->mainConnection->lock());
- return d->activeServices;
-}
-
-/// forces a full update of a service (call this after a failure to connect to the service)
-/// this is an expensive call, use only when needed
-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->setSingleShot(true);
- }
- timer->start(5000);
-}
-
-// signals
-/*!
- \fn void ServiceBrowser::serviceChanged(
- Service::ConstPtr oldService, Service::ConstPtr newService, ServiceBrowser *browser)
-
- This signal is called when a service is added, removed, or changed.
- Both oldService or newService might be null (covers both add and remove).
- The services list might not be synchronized with respect to this signal.
-*/
-/*!
- \fn void ServiceBrowser::serviceAdded(Service::ConstPtr service, ServiceBrowser *browser)
-
- This signal is called when a service is added (convenience method).
- The services list might not be synchronized with respect to this signal.
-
- \sa serviceChanged()
-*/
-/*!
- \fn void ServiceBrowser::serviceRemoved(Service::ConstPtr service, ServiceBrowser *browser)
-
- This signal is called when a service is removed (convenience method).
- The services list might not be synchronized with respect to this signal.
-
- \sa serviceChanged()
-*/
-/*!
- \fn void ServiceBrowser::servicesUpdated(ServiceBrowser *browser)
-
- This signal is called when the list is updated.
- It might collect several serviceChanged signals together. If you use the list
- returned by services(), use this signal, not serviceChanged(), serviceAdded(),
- or serviceRemoved() to learn
- 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 -----------------
-/*!
- Sets the library used by future Service Browsers to preform the mdns queries.
- This changes the default library used by the next MainConnection, it does not change the already
- instantiated connections.
- \a usage can decide which libraries are tried,
- \a libName should be the name (or path) to the libdns library,
- \a daemonPath is the path to the daemon executable which should be started by the embedded library
- if no daemon is found.
-
- \threadsafe
-*/
-void setDefaultZConfLib(LibUsage usage, const QString &avahiLibName, const QString &version,
- const QString &dnsSdLibName,const QString &dnsSdDaemonPath)
-{
- zeroConfLibInstance()->setDefaultLib(usage, avahiLibName, version, dnsSdLibName, dnsSdDaemonPath);
-}
-
-namespace Internal {
-// ----------------- dns-sd C callbacks -----------------
-
-extern "C" void DNSSD_API cServiceResolveReply(DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char *fullname,
- const char *hosttarget,
- uint16_t port, /* In network byte order */
- uint16_t txtLen,
- const unsigned char *txtRecord,
- void *context)
-{
- if (DEBUG_ZEROCONF)
- qDebug() << "cServiceResolveReply(" << ((size_t)sdRef) << ", " << ((quint32)flags)
- << ", " << interfaceIndex << ", " << ((int)errorCode) << ", " << fullname
- << ", " << hosttarget << ", " << qFromBigEndian(port) << ", " << txtLen << ", '"
- << QString::fromUtf8((const char *)txtRecord, txtLen) << "', "
- << ((size_t)context);
- ServiceGatherer *ctxGatherer = reinterpret_cast<ServiceGatherer *>(context);
- if (ctxGatherer){
- if (ctxGatherer->currentService->fullName() != QString::fromLocal8Bit(fullname)) {
- qDebug() << "ServiceBrowser " << ctxGatherer->serviceBrowser->serviceType
- << " for service " << ctxGatherer->currentService->name()
- << " ignoring resolve reply for " << fullname << " vs. "
- << ctxGatherer->currentService->fullName();
- return;
- }
- ctxGatherer->serviceResolveReply(flags, interfaceIndex, errorCode, hosttarget,
- QString::number(qFromBigEndian(port)), txtLen, txtRecord);
- }
-}
-
-extern "C" void DNSSD_API cTxtRecordReply(DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char *fullname,
- uint16_t rrtype,
- uint16_t rrclass,
- uint16_t rdlen,
- const void *rdata,
- uint32_t ttl,
- void *context)
-{
- if (DEBUG_ZEROCONF)
- qDebug() << "cTxtRecordReply(" << ((size_t)sdRef) << ", " << ((int)flags) << ", "
- << interfaceIndex << ", " << ((int)errorCode) << ", " << fullname << ", "
- << rrtype << ", " << rrclass << ", " << ", " << rdlen
- << QString::fromUtf8((const char *)rdata, rdlen) << "', " << ttl << ", "
- << ((size_t)context);
- ServiceGatherer *ctxGatherer = reinterpret_cast<ServiceGatherer *>(context);
- if (ctxGatherer){
- if (rrtype != kDNSServiceType_TXT || rrclass != kDNSServiceClass_IN) {
- qDebug() << "ServiceBrowser " << ctxGatherer->serviceBrowser->serviceType
- << " for service " << ctxGatherer->currentService->fullName()
- << " received an unexpected rrtype/class:" << rrtype << "/" << rrclass;
- }
- ctxGatherer->txtRecordReply(flags, errorCode, rdlen, rdata, ttl);
- }
-}
-
-extern "C" void DNSSD_API cAddrReply(DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char *hostname,
- const struct sockaddr *address,
- uint32_t ttl,
- void *context)
-{
- if (DEBUG_ZEROCONF)
- qDebug() << "cAddrReply(" << ((size_t)sdRef) << ", " << ((int)flags) << ", "
- << interfaceIndex << ", " << ((int)errorCode) << ", " << hostname << ", "
- << QHostAddress(address).toString() << ", " << ttl << ", " << ((size_t)context);
- ServiceGatherer *ctxGatherer = reinterpret_cast<ServiceGatherer *>(context);
- if (ctxGatherer)
- ctxGatherer->addrReply(flags, errorCode, hostname, address, ttl);
-}
-
-/// callback for service browsing
-extern "C" void DNSSD_API cBrowseReply(DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char *serviceName,
- const char *regtype,
- const char *replyDomain,
- void *context)
-{
- if (DEBUG_ZEROCONF)
- qDebug() << "cBrowseReply(" << ((size_t)sdRef) << ", " << flags << ", " << interfaceIndex
- << ", " << ((int)errorCode) << ", " << serviceName << ", " << regtype << ", "
- << replyDomain << ", " << ((size_t)context);
- ServiceBrowserPrivate *sb = (ServiceBrowserPrivate *)(context);
- if (sb == 0){
- qDebug() << "ServiceBrowser ignoring reply because context was null ";
- return;
- }
- sb->browseReply(flags, interfaceIndex, ZK_PROTO_IPv4_OR_IPv6,
- errorCode, serviceName, regtype, replyDomain);
-}
-
-// ----------------- ConnectionThread impl -----------------
-
-void ConnectionThread::run()
-{
-#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
- struct sigaction act;
- // ignore SIGPIPE
- act.sa_handler=SIG_IGN;
- sigemptyset(&act.sa_mask);
- act.sa_flags=0;
- sigaction(SIGPIPE, &act, NULL);
-#endif
- connection.handleEvents();
-}
-
-ConnectionThread::ConnectionThread(MainConnection &mc, QObject *parent):
- QThread(parent), connection(mc)
-{ }
-
-// ----------------- ServiceGatherer impl -----------------
-
-ZConfLib::Ptr ServiceGatherer::lib()
-{
- return serviceBrowser->mainConnection->lib;
-}
-
-QString ServiceGatherer::fullName(){
- return currentService->fullName();
-}
-
-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);
- 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()
-{
- if (publishedService) {
- if (DEBUG_ZEROCONF)
- qDebug() << "ServiceGatherer::retireService() for service "
- << currentService->fullName();
- Service::Ptr nService;
- serviceBrowser->nextActiveServices.removeOne(publishedService);
- 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 "
- << currentService->fullName();
- }
-}
-
-void ServiceGatherer::stopResolve(ZK_IP_Protocol protocol)
-{
- if ((protocol == ZK_PROTO_IPv4_OR_IPv6 || protocol == ZK_PROTO_IPv4)
- && (status & ResolveConnectionActive) != 0) {
- QMutexLocker l(serviceBrowser->mainConnection->lock());
- if (serviceBrowser->mainConnection->status() < MainConnection::Stopping)
- lib()->refDeallocate(resolveConnection);
- status &= ~ResolveConnectionActive;
- serviceBrowser->updateFlowStatusForCancel();
- }
- if ((protocol == ZK_PROTO_IPv4_OR_IPv6 || protocol == ZK_PROTO_IPv6)
- && (status & ResolveConnectionV6Active) != 0) {
- QMutexLocker l(serviceBrowser->mainConnection->lock());
- if (serviceBrowser->mainConnection->status() < MainConnection::Stopping)
- lib()->refDeallocate(resolveConnectionV6);
- status &= ~ResolveConnectionV6Active;
- serviceBrowser->updateFlowStatusForCancel();
- }
-}
-
-void ServiceGatherer::restartResolve(ZK_IP_Protocol protocol)
-{
- stopResolve(protocol);
- if (protocol == ZK_PROTO_IPv6) {
- if (currentService->host()) {
- QList<QHostAddress> addrNow = currentService->host()->addresses();
- QMutableListIterator<QHostAddress> addr(addrNow);
- bool changed = false;
- while (addr.hasNext()) {
- if (addr.next().protocol() == QAbstractSocket::IPv6Protocol) {
- addr.remove();
- changed = true;
- }
- }
- if (changed)
- currentService->m_host->setAddresses(addrNow);
- }
- DNSServiceErrorType err = lib()->resolve(
- serviceBrowser->mainRef(),
- &resolveConnectionV6,
- currentService->interfaceNr(), protocol,
- currentService->name().toUtf8().constData(),
- currentService->type().toUtf8().constData(),
- currentService->domain().toUtf8().constData(), this);
- if (err != kDNSServiceErr_NoError) {
- qDebug() << "ServiceBrowser " << serviceBrowser->serviceType
- << " failed IPv6 discovery of service " << currentService->fullName()
- << " due to error " << err;
- status = status | ResolveConnectionV6Failed;
- } else {
- status = ((status & ~ResolveConnectionV6Failed) | ResolveConnectionV6Active);
- }
- } else {
- if (currentService->host()) {
- if (protocol == ZK_PROTO_IPv4_OR_IPv6) {
- currentService->m_host->setAddresses(QList<QHostAddress>());
- } else {
- QList<QHostAddress> addrNow = currentService->host()->addresses();
- QMutableListIterator<QHostAddress> addr(addrNow);
- bool changed = false;
- while (addr.hasNext()) {
- if (addr.next().protocol() == QAbstractSocket::IPv4Protocol) {
- addr.remove();
- changed = true;
- }
- }
- if (changed)
- currentService->m_host->setAddresses(addrNow);
- }
- }
- DNSServiceErrorType err = lib()->resolve(
- serviceBrowser->mainRef(),
- &resolveConnection,
- currentService->interfaceNr(), protocol,
- currentService->name().toUtf8().constData(),
- currentService->type().toUtf8().constData(),
- currentService->domain().toUtf8().constData(), this);
- if (err != kDNSServiceErr_NoError) {
- qDebug() << "ServiceBrowser " << serviceBrowser->serviceType
- << " failed discovery of service " << currentService->fullName()
- << " due to error " << err;
- status = status | ResolveConnectionFailed;
- } else {
- status = ((status & ~ResolveConnectionFailed) | ResolveConnectionActive);
- }
- }
-}
-
-void ServiceGatherer::stopTxt()
-{
- if ((status & TxtConnectionActive) == 0) return;
- QMutexLocker l(serviceBrowser->mainConnection->lock());
- if (serviceBrowser->mainConnection->status() < MainConnection::Stopping)
- lib()->refDeallocate(txtConnection);
- status &= ~TxtConnectionActive;
- serviceBrowser->updateFlowStatusForCancel();
-}
-
-void ServiceGatherer::restartTxt()
-{
- stopTxt();
- DNSServiceErrorType err = lib()->queryRecord(serviceBrowser->mainRef(), &txtConnection,
- currentService->interfaceNr(),
- currentService->fullName().toUtf8().constData(),
- this);
-
- if (err != kDNSServiceErr_NoError) {
- qDebug() << "ServiceBrowser " << serviceBrowser->serviceType
- << " failed query of TXT record of service " << currentService->fullName()
- << " due to error " << err;
- status = status | TxtConnectionFailed;
- } else {
- status = ((status & ~TxtConnectionFailed) | TxtConnectionActive);
- }
-}
-
-void ServiceGatherer::stopHostResolution()
-{
- if ((status & AddrConnectionActive) == 0) return;
- QMutexLocker l(serviceBrowser->mainConnection->lock());
- if (serviceBrowser->mainConnection->status() < MainConnection::Stopping)
- lib()->refDeallocate(addrConnection);
- status &= ~AddrConnectionActive;
- serviceBrowser->updateFlowStatusForCancel();
-}
-
-void ServiceGatherer::restartHostResolution()
-{
- stopHostResolution();
- if (DEBUG_ZEROCONF)
- qDebug() << "ServiceGatherer::restartHostResolution for host " << hostName << " service "
- << currentService->fullName();
- if (hostName.isEmpty()){
- qDebug() << "ServiceBrowser " << serviceBrowser->serviceType
- << " cannot start host resolution without hostname for service "
- << currentService->fullName();
- }
- DNSServiceErrorType err = lib()->getAddrInfo(serviceBrowser->mainRef(), &addrConnection,
- currentService->interfaceNr(),
- 0 /* kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6 */,
- hostName.toUtf8().constData(), this);
-
- if (err != kDNSServiceErr_NoError) {
- qDebug() << "ServiceBrowser " << serviceBrowser->serviceType
- << " failed starting resolution of host " << hostName << " for service "
- << currentService->fullName() << " due to error " << err;
- status = status | AddrConnectionFailed;
- } else {
- status = ((status & ~AddrConnectionFailed) | AddrConnectionActive);
- }
-}
-
-/// if the current service can be added
-bool ServiceGatherer::currentServiceCanBePublished()
-{
- return (currentService->host() && !currentService->host()->addresses().isEmpty())
- || !serviceBrowser->requireAddresses;
-}
-
-ServiceGatherer::ServiceGatherer(const QString &newServiceName, const QString &newType,
- const QString &newDomain, const QString &fullName,
- uint32_t interfaceIndex, ZK_IP_Protocol protocol,
- ServiceBrowserPrivate *serviceBrowser):
- serviceBrowser(serviceBrowser), publishedService(0), currentService(new Service()), status(0)
-{
- if (DEBUG_ZEROCONF)
- qDebug() << " creating ServiceGatherer(" << newServiceName << ", " << newType << ", "
- << newDomain << ", " << fullName << ", " << interfaceIndex << ", "
- << ((size_t) serviceBrowser);
- currentService->m_name = newServiceName;
- currentService->m_type = newType;
- currentService->m_domain = newDomain;
- currentService->m_fullName = fullName;
- currentService->m_interfaceNr = interfaceIndex;
- if (fullName.isEmpty())
- currentService->m_fullName = toFullNameC(currentService->name().toUtf8().data(),
- currentService->type().toUtf8().data(),
- currentService->domain().toUtf8().data());
- restartResolve(protocol);
- restartTxt();
-}
-
-ServiceGatherer::~ServiceGatherer()
-{
- stopHostResolution();
- stopResolve();
- stopTxt();
- delete currentService;
-}
-
-ServiceGatherer::Ptr ServiceGatherer::createGatherer(
- const QString &newServiceName, const QString &newType, const QString &newDomain,
- const QString &fullName, uint32_t interfaceIndex, ZK_IP_Protocol protocol,
- ServiceBrowserPrivate *serviceBrowser)
-{
- Ptr res(new ServiceGatherer(newServiceName, newType, newDomain, fullName, interfaceIndex,
- protocol, serviceBrowser));
- res->self = res.toWeakRef();
- return res;
-}
-
-ServiceGatherer::Ptr ServiceGatherer::gatherer() {
- return self.toStrongRef();
-}
-
-void ServiceGatherer::serviceResolveReply(DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char *hosttarget,
- const QString &port,
- uint16_t txtLen,
- const unsigned char *rawTxtRecord)
-{
- if (errorCode != kDNSServiceErr_NoError){
- if (errorCode == kDNSServiceErr_Timeout){
- if ((status & ResolveConnectionSuccess) == 0){
- qDebug() << "ServiceBrowser " << serviceBrowser->serviceType
- << " failed service resolution for service "
- << currentService->fullName() << " as it did timeout";
- status |= ResolveConnectionFailed;
- }
- } else {
- qDebug() << "ServiceBrowser " << serviceBrowser->serviceType
- << " failed service resolution for service " << currentService->fullName()
- << " with error " << errorCode;
- status |= ResolveConnectionFailed;
- }
- if (status & ResolveConnectionActive) {
- status &= ~ResolveConnectionActive;
- lib()->refDeallocate(resolveConnection);
- serviceBrowser->updateFlowStatusForCancel();
- }
- return;
- }
- serviceBrowser->updateFlowStatusForFlags(flags);
- uint16_t nKeys = txtRecordGetCount(txtLen, rawTxtRecord);
- for (uint16_t i = 0; i < nKeys; ++i){
- enum { maxTxtLen = 256 };
- char keyBuf[maxTxtLen];
- uint8_t valLen;
- const char *valueCStr;
- DNSServiceErrorType txtErr = txtRecordGetItemAtIndex(
- txtLen, rawTxtRecord, i, maxTxtLen, keyBuf, &valLen, (const void **)&valueCStr);
- if (txtErr != kDNSServiceErr_NoError){
- qDebug() << "ServiceBrowser " << serviceBrowser->serviceType << " error " << txtErr
- << " decoding txt record of service " << currentService->fullName();
- break;
- }
- keyBuf[maxTxtLen-1] = 0; // just to be sure
- currentService->m_txtRecord.insert(QString::fromUtf8(keyBuf),
- QString::fromUtf8(valueCStr, valLen));
- }
- currentService->m_interfaceNr = interfaceIndex;
- currentService->m_port = port;
- if (hostName != QString::fromUtf8(hosttarget)) {
- hostName = QString::fromUtf8(hosttarget);
- if (!currentService->host())
- currentService->m_host = new QHostInfo();
- else
- currentService->m_host->setAddresses(QList<QHostAddress>());
- currentService->m_host->setHostName(hostName);
- if (serviceBrowser->autoResolveAddresses)
- restartHostResolution();
- }
- if (currentServiceCanBePublished())
- serviceBrowser->pendingGathererAdd(gatherer());
-}
-
-void ServiceGatherer::txtRecordReply(DNSServiceFlags flags,
- DNSServiceErrorType errorCode,
- uint16_t txtLen,
- const void *rawTxtRecord,
- uint32_t /*ttl*/)
-{
- if (errorCode != kDNSServiceErr_NoError){
- if (errorCode == kDNSServiceErr_Timeout){
- if ((status & TxtConnectionSuccess) == 0){
- qDebug() << "ServiceBrowser " << serviceBrowser->serviceType
- << " failed txt gathering for service " << currentService->fullName()
- << " as it did timeout";
- status |= TxtConnectionFailed;
- }
- } else {
- qDebug() << "ServiceBrowser " << serviceBrowser->serviceType
- << " failed txt gathering for service " << currentService->fullName()
- << " with error " << errorCode;
- status |= TxtConnectionFailed;
- }
- if (status & TxtConnectionActive) {
- status &= ~TxtConnectionActive;
- lib()->refDeallocate(txtConnection);
- serviceBrowser->updateFlowStatusForCancel();
- }
- return;
- }
- serviceBrowser->updateFlowStatusForFlags(flags);
-
- uint16_t nKeys = txtRecordGetCount(txtLen, rawTxtRecord);
- for (uint16_t i = 0; i < nKeys; ++i){
- char keyBuf[256];
- uint8_t valLen;
- const char *valueCStr;
- DNSServiceErrorType txtErr = txtRecordGetItemAtIndex(txtLen, rawTxtRecord, i, 256, keyBuf,
- &valLen, (const void **)&valueCStr);
- if (txtErr != kDNSServiceErr_NoError){
- qDebug() << "ServiceBrowser " << serviceBrowser->serviceType << " error " << txtErr
- << " decoding txt record of service " << currentService->fullName();
- if ((flags & kDNSServiceFlagsAdd) == 0)
- currentService->m_txtRecord.clear();
- break;
- }
- keyBuf[255] = 0; // just to be sure
- if (flags & kDNSServiceFlagsAdd) {
- currentService->m_txtRecord.insert(QString::fromUtf8(keyBuf),
- QString::fromUtf8(valueCStr, valLen));
- } else {
- currentService->m_txtRecord.remove(QString::fromUtf8(keyBuf)); // check value???
- }
- }
- if ((flags & kDNSServiceFlagsAdd) != 0)
- status |= TxtConnectionSuccess;
- if (currentService->m_txtRecord.count() != 0 && currentServiceCanBePublished())
- serviceBrowser->pendingGathererAdd(gatherer());
-}
-
-void ServiceGatherer::txtFieldReply(DNSServiceFlags flags,
- DNSServiceErrorType errorCode,
- uint16_t txtLen,
- const void *rawTxtRecord,
- uint32_t /*ttl*/){
- if (errorCode != kDNSServiceErr_NoError){
- if (errorCode == kDNSServiceErr_Timeout){
- if ((status & TxtConnectionSuccess) == 0){
- qDebug() << "ServiceBrowser " << serviceBrowser->serviceType
- << " failed txt gathering for service " << currentService->fullName()
- << " as it did timeout";
- status |= TxtConnectionFailed;
- }
- } else {
- qDebug() << "ServiceBrowser " << serviceBrowser->serviceType
- << " failed txt gathering for service " << currentService->fullName()
- << " with error " << errorCode;
- status |= TxtConnectionFailed;
- }
- if (status & TxtConnectionActive) {
- status &= ~TxtConnectionActive;
- lib()->refDeallocate(txtConnection);
- serviceBrowser->updateFlowStatusForCancel();
- }
- return;
- }
- serviceBrowser->updateFlowStatusForFlags(flags);
- uint16_t keyLen = 0;
- const char *txt = reinterpret_cast<const char *>(rawTxtRecord);
- while (keyLen < txtLen) {
- if (txt[keyLen]=='=')
- break;
- ++keyLen;
- }
- if (flags & kDNSServiceFlagsAdd) {
- currentService->m_txtRecord.insert(
- QString::fromUtf8(txt, keyLen),
- QString::fromUtf8(txt + keyLen + 1, ((txtLen > keyLen)?txtLen - keyLen - 1:0)));
- } else {
- currentService->m_txtRecord.remove(QString::fromUtf8(txt, keyLen)); // check value???
- }
-
-}
-
-void ServiceGatherer::addrReply(DNSServiceFlags flags,
- DNSServiceErrorType errorCode,
- const char *hostname,
- const struct sockaddr *address,
- uint32_t /*ttl*/) // should we use this???
-{
- if (errorCode != kDNSServiceErr_NoError) {
- if (errorCode == kDNSServiceErr_Timeout){
- if ((status & AddrConnectionSuccess) == 0){
- qDebug() << "ServiceBrowser " << serviceBrowser->serviceType
- << " failed address resolve for service " << currentService->fullName()
- << " as it did timeout";
- status |= AddrConnectionFailed;
- }
- qDebug() << "ServiceBrowser " << serviceBrowser->serviceType
- << " failed addr resolve for service " << currentService->fullName()
- << " with error " << errorCode;
- status |= AddrConnectionFailed;
- }
- if (status & AddrConnectionActive){
- status &= ~AddrConnectionActive;
- lib()->refDeallocate(addrConnection);
- serviceBrowser->updateFlowStatusForCancel();
- }
- return;
- }
- serviceBrowser->updateFlowStatusForFlags(flags);
- if (!currentService->host())
- currentService->m_host = new QHostInfo();
- if (currentService->host()->hostName() != QString::fromUtf8(hostname)) {
- if ((flags & kDNSServiceFlagsAdd) == 1)
- currentService->m_host->setHostName(QString::fromUtf8(hostname));
- if (currentService->host()->addresses().isEmpty()) {
- qDebug() << "ServiceBrowser " << serviceBrowser->serviceType << " for service "
- << currentService->fullName() << " add with name " << hostname
- << " while old name " << currentService->host()->hostName()
- << " has still adresses, removing them";
- currentService->m_host->setAddresses(QList<QHostAddress>());
- } else {
- qDebug() << "ServiceBrowser " << serviceBrowser->serviceType << " for service "
- << currentService->fullName() << " ignoring remove for " << hostname
- << " as current hostname is " << currentService->host()->hostName();
- return;
- }
- }
- QHostAddress newAddr(address);
- QList<QHostAddress> addrNow = currentService->host()->addresses();
- if ((flags & kDNSServiceFlagsAdd) == 0) {
- if (addrNow.removeOne(newAddr))
- currentService->m_host->setAddresses(addrNow);
- } else {
- if (!addrNow.contains(newAddr)){
- switch (newAddr.protocol()){
-#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);
- break;
- }
- currentService->m_host->setAddresses(addrNow);
- }
- }
- serviceBrowser->pendingGathererAdd(gatherer());
-}
-
-void ServiceGatherer::maybeRemove()
-{
- // could trigger an update, but for now we just ignore it (less chatty)
-}
-
-void ServiceGatherer::stop(ZK_IP_Protocol protocol)
-{
- if ((protocol == ZK_PROTO_IPv4_OR_IPv6 || protocol == ZK_PROTO_IPv4)
- && (status & ResolveConnectionActive) != 0){
- status &= ~ResolveConnectionActive;
- lib()->refDeallocate(resolveConnection);
- serviceBrowser->updateFlowStatusForCancel();
- }
- if ((protocol == ZK_PROTO_IPv4_OR_IPv6 || protocol == ZK_PROTO_IPv6)
- && (status & ResolveConnectionV6Active) != 0){
- status &= ~ResolveConnectionV6Active;
- lib()->refDeallocate(resolveConnectionV6);
- serviceBrowser->updateFlowStatusForCancel();
- }
- if (status & TxtConnectionActive){
- status &= ~TxtConnectionActive;
- lib()->refDeallocate(txtConnection);
- serviceBrowser->updateFlowStatusForCancel();
- }
- if (status & AddrConnectionActive) {
- status &= ~AddrConnectionActive;
- lib()->refDeallocate(addrConnection);
- serviceBrowser->updateFlowStatusForCancel();
- }
-}
-
-void ServiceGatherer::reload(qint32 interfaceIndex, ZK_IP_Protocol protocol)
-{
- this->interfaceIndex = interfaceIndex;
- stop(protocol);
- restartResolve(protocol);
- restartTxt();
- if (currentServiceCanBePublished()) // avoid???
- restartHostResolution();
-}
-
-void ServiceGatherer::remove()
-{
- stop();
- if (serviceBrowser->gatherers.contains(currentService->fullName())
- && serviceBrowser->gatherers[currentService->fullName()] == this)
- {
- serviceBrowser->gatherers.remove(currentService->fullName());
- }
-}
-/// forces a full reload of the record
-void ServiceGatherer::reconfirm()
-{
- stop();
- /* DNSServiceErrorType err = DNSServiceReconfirmRecord(kDNSServiceFlagsShareConnection,
- interfaceIndex, fullName.toUtf8().constData(),
- kDNSServiceType_PTR, // kDNSServiceType_SRV could be another possibility
- kDNSServiceClass_IN //,
- // uint16_t rdlen, // not cached... what is the best solution???
- // const void *rdata
- ); */
-}
-
-// ----------------- ServiceBrowserPrivate impl -----------------
-
-ZConfLib::ConnectionRef ServiceBrowserPrivate::mainRef()
-{
- return mainConnection->mainRef();
-}
-
-void ServiceBrowserPrivate::updateFlowStatusForCancel()
-{
- mainConnection->updateFlowStatusForCancel();
-}
-
-void ServiceBrowserPrivate::updateFlowStatusForFlags(DNSServiceFlags flags)
-{
- mainConnection->updateFlowStatusForFlags(flags);
-}
-
-void ServiceBrowserPrivate::pendingGathererAdd(ServiceGatherer::Ptr gatherer)
-{
- int ng = pendingGatherers.count();
- for (int i = 0; i < ng; ++i){
- const ServiceGatherer::Ptr &g = pendingGatherers.at(i);
- if (g->fullName() == gatherer->fullName()){
- if (g != gatherer){
- gatherer->publishedService = g->publishedService;
- pendingGatherers[i] = gatherer;
- }
- return;
- }
- }
- pendingGatherers.append(gatherer);
-}
-
-ServiceBrowserPrivate::ServiceBrowserPrivate(const QString &serviceType, const QString &domain,
- bool requireAddresses, MainConnectionPtr mconn):
- q(0), serviceType(serviceType), domain(domain), mainConnection(mconn), serviceConnection(0), flags(0), interfaceIndex(0),
- delayDeletesUntil(std::numeric_limits<qint64>::min()), failed(false), browsing(false),
- autoResolveAddresses(requireAddresses), requireAddresses(requireAddresses), shouldRefresh(false)
-{
-}
-
-ServiceBrowserPrivate::~ServiceBrowserPrivate()
-{
- if (DEBUG_ZEROCONF)
- qDebug() << "destroying ServiceBrowserPrivate " << serviceType;
- if (browsing)
- stopBrowsing();
- if (mainConnection)
- mainConnection->removeBrowser(this);
-}
-
-void ServiceBrowserPrivate::insertGatherer(const QString &fullName)
-{
- if (!gatherers.contains(fullName)){
- QString newServiceName, newType, newDomain;
- if (fromFullNameC(fullName.toUtf8().data(), *&newServiceName, *&newType, *&newDomain)){
- qDebug() << "Error unescaping fullname " << fullName;
- } else {
- ServiceGatherer::Ptr serviceGatherer = ServiceGatherer::createGatherer(
- newServiceName, newType, newDomain, fullName, 0, ZK_PROTO_IPv4_OR_IPv6, this);
- gatherers[fullName] = serviceGatherer;
- }
- }
-}
-
-void ServiceBrowserPrivate::maybeUpdateLists()
-{
- if (mainConnection->flowStatus != MainConnection::MoreComingRFS
- || pendingGatherers.count() > 50 || shouldRefresh)
- {
- 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();
- if (vi == vj){
- ++i;
- ++j;
- } else if (vi < vj) {
- qDebug() << "ServiceBrowser " << serviceType << ", missing gatherer for " << vi;
- insertGatherer(vi);
- ++i;
- } else if (delayDeletesUntil <= now) {
- pendingGatherers.removeAll(j.value());
- j.value()->retireService();
- j = gatherers.erase(j);
- hasServicesChanges = true;
- } else {
- ++j;
- }
- }
- while (i != endi) {
- qDebug() << "ServiceBrowser " << serviceType << ", missing gatherer for " << *i;
- insertGatherer(*i);
- }
- while (j != gatherers.end()) {
- if (delayDeletesUntil <= now) {
- pendingGatherers.removeAll(j.value());
- j.value()->retireService();
- j = gatherers.erase(j);
- hasServicesChanges = true;
- } else {
- ++j;
- }
- }
- foreach (const ServiceGatherer::Ptr &g, pendingGatherers)
- if (delayDeletesUntil <= now || ! g->publishedService)
- hasServicesChanges = g->enactServiceChange() || hasServicesChanges;
- if (hasServicesChanges) {
- {
- QMutexLocker l(mainConnection->lock());
- activeServices = nextActiveServices;
- }
- emit q->servicesUpdated(q);
- }
- }
- {
- QMutexLocker l(mainConnection->lock());
- if (shouldRefresh)
- refresh();
- }
-}
-
-/// callback announcing
-void ServiceBrowserPrivate::browseReply(DNSServiceFlags flags,
- uint32_t interfaceIndex,
- ZK_IP_Protocol protocol,
- DNSServiceErrorType errorCode,
- const char *serviceName,
- const char *regtype,
- const char *replyDomain)
-{
- if (DEBUG_ZEROCONF)
- qDebug() << "browseReply(" << ((int)flags) << ", " << interfaceIndex << ", "
- << ((int)errorCode) << ", " << serviceName << ", " << regtype << ", "
- << replyDomain << ")";
- if (errorCode != kDNSServiceErr_NoError){
- qDebug() << "ServiceBrowser " << serviceType << " ignoring reply due to error " << errorCode;
- return;
- }
- QString newServiceName = QString::fromUtf8(serviceName);
- QString newType = serviceType;
- QString newDomain = domain;
- if (serviceType != QString::fromUtf8(regtype)) // discard? should not happen...
- newType = QString::fromUtf8(regtype);
- if (domain != QString::fromUtf8(replyDomain))
- domain = QString::fromUtf8(replyDomain);
- QString fullName = toFullNameC(serviceName, regtype, replyDomain);
- updateFlowStatusForFlags(flags);
- if (flags & kDNSServiceFlagsAdd){
- ServiceGatherer::Ptr serviceGatherer;
- if (!gatherers.contains(fullName)){
- serviceGatherer = ServiceGatherer::createGatherer(newServiceName, newType, newDomain,
- fullName, interfaceIndex, protocol,
- this);
- gatherers[fullName] = serviceGatherer;
- } else {
- serviceGatherer = gatherers[fullName];
- serviceGatherer->reload(interfaceIndex, protocol);
- }
- QList<QString>::iterator pos = std::lower_bound(knownServices.begin(), knownServices.end(),
- fullName);
- // could order later (more efficient, but then we have to handle eventual duplicates)
- if (pos == knownServices.end() || *pos != fullName)
- knownServices.insert(pos, fullName);
- } else {
- if (gatherers.contains(fullName))
- gatherers[fullName]->maybeRemove();
- knownServices.removeOne(fullName);
- }
- maybeUpdateLists(); // avoid?
-}
-
-void ServiceBrowserPrivate::activateAutoRefresh()
-{
- emit q->activateAutoRefresh();
-}
-
-void ServiceBrowserPrivate::startBrowsing(quint32 interfaceIndex)
-{
- this->interfaceIndex = interfaceIndex;
- if (failed || browsing)
- return;
- if (mainConnection.isNull()) {
- startupPhase(1, ServiceBrowser::tr("Starting Zeroconf Browsing"));
- mainConnection = MainConnectionPtr(new MainConnection(this));
- } else {
- mainConnection->addBrowser(this);
- }
-}
-
-bool ServiceBrowserPrivate::internalStartBrowsing()
-{
- mainConnection->updateFlowStatusForFlags(0);
- if (failed || browsing)
- return false;
- DNSServiceErrorType err;
- err = mainConnection->lib->browse(mainRef(), &serviceConnection, interfaceIndex,
- serviceType.toUtf8().constData(),
- ((domain.isEmpty()) ? 0 : (domain.toUtf8().constData())), this);
- if (err != kDNSServiceErr_NoError){
- qDebug() << "ServiceBrowser " << serviceType << " failed initializing serviceConnection";
- return false;
- }
- browsing = true;
- if (DEBUG_ZEROCONF)
- qDebug() << "startBrowsing(" << interfaceIndex << ") for serviceType:" << serviceType
- << " domain:" << domain;
- return true;
-}
-
-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()
-{
- const qint64 msecDelay = 500;
- delayDeletesUntil = QDateTime::currentMSecsSinceEpoch() + msecDelay;
- shouldRefresh = false;
- internalStartBrowsing();
-}
-
-
-void ServiceBrowserPrivate::stopBrowsing()
-{
- QMutexLocker l(mainConnection->lock());
- if (browsing){
- if (serviceConnection) {
- mainConnection->lib->browserDeallocate(&serviceConnection);
- updateFlowStatusForCancel();
- serviceConnection = 0;
- }
- knownServices.clear();
- browsing = false;
- }
-}
-
-void ServiceBrowserPrivate::reconfirmService(Service::ConstPtr s)
-{
- if (!s->outdated())
- mainConnection->lib->reconfirmRecord(
- mainRef(), s->interfaceNr(), s->name().toUtf8().data(),
- s->type().toUtf8().data(), s->domain().toUtf8().data(),
- s->fullName().toUtf8().data());
-}
-
-/// called when a service is added removed or changes. oldService or newService might be null
-/// (covers both add and remove)
-void ServiceBrowserPrivate::serviceChanged(const Service::ConstPtr &oldService,
- const Service::ConstPtr &newService,
- ServiceBrowser *browser)
-{
- emit q->serviceChanged(oldService, newService, browser);
-}
-
-/// called when a service is added (utility method)
-void ServiceBrowserPrivate::serviceAdded(const Service::ConstPtr &service, ServiceBrowser *browser)
-{
- emit q->serviceAdded(service, browser);
-}
-
-/// called when a service is removed (utility method)
-void ServiceBrowserPrivate::serviceRemoved(const Service::ConstPtr &service, ServiceBrowser *browser)
-{
- emit q->serviceRemoved(service, browser);
-}
-
-/// called when the list is updated (this might collect several serviceChanged signals together)
-void ServiceBrowserPrivate::servicesUpdated(ServiceBrowser *browser)
-{
- emit q->servicesUpdated(browser);
-}
-
-/// called to describe the current startup phase
-void ServiceBrowserPrivate::startupPhase(int progress, const QString &description)
-{
- emit q->startupPhase(progress, description, q);
-}
-
-
-/// called when there is an error message
-void ServiceBrowserPrivate::errorMessage(ErrorMessage::SeverityLevel severity, const QString &msg)
-{
- if (severity == ErrorMessage::FailureLevel)
- this->failed = true;
- emit q->errorMessage(severity, msg, q);
-}
-
-/// called when the browsing fails
-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)
-{
- {
- if (QThread::currentThread() == m_thread)
- qCritical() << "ERROR ZerocConf::MainConnection::stop called from m_thread";
- // This will most likely lock if called from the connection thread (as mainThreadLock is non recusive)
- // Making it recursive would open a hole during the startup of the thread.
- // As of now this should always be called during the destruction of a browser,
- // so from another thread.
- increaseStatusTo(Stopping);
- QMutexLocker l(mainThreadLock());
- QMutexLocker l2(lock());
- }
- if (m_mainRef) {
- lib->stopConnection(m_mainRef);
- m_mainRef = 0;
- }
- if (!m_thread)
- increaseStatusTo(Stopped);
- else if (wait && QThread::currentThread() != m_thread)
- m_thread->wait();
-}
-
-MainConnection::MainConnection(ServiceBrowserPrivate *initialBrowser):
- flowStatus(NormalRFS),
- lib(zeroConfLibInstance()->defaultLib()), m_lock(QMutex::Recursive),
- m_mainThreadLock(QMutex::NonRecursive), m_mainRef(0), m_failed(false), m_status(Starting), m_nErrs(0)
-{
- if (initialBrowser)
- addBrowser(initialBrowser);
- if (lib.isNull()){
- appendError(ErrorMessage::FailureLevel, tr("Zeroconf could not load a valid library, failing."));
- } else {
- m_thread = new ConnectionThread(*this);
- m_mainThreadLock.lock();
- m_thread->start(); // delay startup??
- }
-}
-
-MainConnection::~MainConnection()
-{
- gQuickStop = 1;
- stop(true);
- gQuickStop = 0;
- delete m_thread;
-}
-
-bool MainConnection::increaseStatusTo(int s)
-{
- int sAtt = status();
- while (sAtt < s){
- if (m_status.testAndSetRelaxed(sAtt, s))
- return true;
- sAtt = status();
- }
- return false;
-}
-
-QMutex *MainConnection::lock()
-{
- return &m_lock;
-}
-
-QMutex *MainConnection::mainThreadLock()
-{
- return &m_mainThreadLock;
-}
-
-void MainConnection::waitStartup()
-{
- int sAtt;
- while (true){
- {
- QMutexLocker l(lock());
- sAtt = status();
- if (sAtt >= Running)
- return;
- }
- QThread::yieldCurrentThread();
- }
-}
-
-void MainConnection::addBrowser(ServiceBrowserPrivate *browser)
-{
- int actualStatus;
- QList<ErrorMessage> errs;
- {
- QMutexLocker l(lock());
- actualStatus = status();
- m_browsers.append(browser);
- errs = m_errors;
- }
- if (actualStatus == Running && browser->internalStartBrowsing())
- browser->startedBrowsing();
- bool didFail = false;
- foreach (const ErrorMessage &msg, errs) {
- browser->errorMessage(msg.severity, msg.msg);
- didFail = didFail || msg.severity == ErrorMessage::FailureLevel;
- }
- if (didFail)
- browser->hadFailure(errs);
-}
-
-void MainConnection::removeBrowser(ServiceBrowserPrivate *browser)
-{
- QMutexLocker l(lock());
- m_browsers.removeOne(browser);
-}
-
-void MainConnection::updateFlowStatusForCancel(){
- flowStatus = ForceUpdateRFS;
-}
-void MainConnection::updateFlowStatusForFlags(DNSServiceFlags flags)
-{
- if (flags & kDNSServiceFlagsMoreComing) {
- if (flowStatus == NormalRFS)
- flowStatus = MoreComingRFS;
- } else {
- flowStatus = NormalRFS;
- }
-}
-void MainConnection::maybeUpdateLists()
-{
- foreach (ServiceBrowserPrivate *sb, m_browsers) {
- sb->maybeUpdateLists();
- }
-}
-
-void MainConnection::gotoValidLib(){
- while (lib){
- if (lib->isOk()) break;
- appendError(ErrorMessage::WarningLevel, tr("Zeroconf giving up on non working %1 (%2).")
- .arg(lib->name()).arg(lib->errorMsg()));
- lib = lib->fallbackLib;
- }
- if (!lib) {
- appendError(ErrorMessage::FailureLevel, tr("Zeroconf has no valid library, aborting connection."));
- increaseStatusTo(Stopping);
- }
-}
-
-void MainConnection::abortLib(){
- if (!lib){
- appendError(ErrorMessage::FailureLevel, tr("Zeroconf has no valid library, aborting connection."));
- increaseStatusTo(Stopping);
- } else if (lib->fallbackLib){
- appendError(ErrorMessage::WarningLevel, tr("Zeroconf giving up on %1, switching to %2.")
- .arg(lib->name()).arg(lib->fallbackLib->name()));
- lib = lib->fallbackLib;
- m_nErrs = 0;
- gotoValidLib();
- } else {
- appendError(ErrorMessage::FailureLevel, tr("Zeroconf giving up on %1, no fallback provided, aborting connection.")
- .arg(lib->name()));
- increaseStatusTo(Stopping);
- }
-}
-
-void MainConnection::createConnection()
-{
- gotoValidLib();
- while (status() <= Running) {
- if (!lib) {
- increaseStatusTo(Stopped);
- break;
- }
- startupPhase(m_nErrs + zeroConfLibInstance()->nFallbacksTot() - lib->nFallbacks() + 2,
- tr("Trying %1...").arg(lib->name()));
- uint32_t version;
- uint32_t size = (uint32_t)sizeof(uint32_t);
- DNSServiceErrorType err = lib->getProperty(kDNSServiceProperty_DaemonVersion, &version, &size);
- if (err == kDNSServiceErr_NoError){
- DNSServiceErrorType error = lib->createConnection(this, &m_mainRef);
- if (error != kDNSServiceErr_NoError){
- appendError(ErrorMessage::WarningLevel, tr("Zeroconf using %1 failed the initialization of the main library connection with error %2.")
- .arg(lib->name()).arg(error));
- ++m_nErrs;
- if (m_nErrs > lib->nFallbacks() || !lib->isOk())
- abortLib();
- } else {
- QList<ServiceBrowserPrivate *> waitingBrowsers;
- {
- QMutexLocker l(lock());
- waitingBrowsers = m_browsers;
- increaseStatusTo(Running);
- }
- for (int i = waitingBrowsers.count(); i-- != 0; ){
- ServiceBrowserPrivate *actualBrowser = waitingBrowsers[i];
- if (actualBrowser && !actualBrowser->browsing
- && actualBrowser->internalStartBrowsing())
- actualBrowser->startedBrowsing();
- }
- break;
- }
- } else if (err == kDNSServiceErr_ServiceNotRunning) {
- appendError(ErrorMessage::WarningLevel, tr("Zeroconf using %1 failed because no daemon is running.")
- .arg(lib->name()));
- ++m_nErrs;
- if (m_nErrs > lib->maxErrors() || !lib->isOk()) {
- abortLib();
- } else if (lib->tryStartDaemon(this)) {
- appendError(ErrorMessage::WarningLevel, tr("Starting the Zeroconf daemon using %1 seems successful, continuing.")
- .arg(lib->name()));
- } else {
- appendError(ErrorMessage::WarningLevel, tr("Zeroconf using %1 failed because no daemon is running.")
- .arg(lib->name()));
- abortLib();
- }
- } else {
- appendError(ErrorMessage::WarningLevel, tr("Zeroconf using %1 failed getProperty call with error %2.")
- .arg(lib->name()).arg(err));
- abortLib();
- }
- }
- if (status() < Stopping) {
- startupPhase(zeroConfLibInstance()->nFallbacksTot() + 3, tr("Succeeded using %1.").arg(lib->name()));
- appendError(ErrorMessage::NoteLevel,
- tr("MainConnection could successfully create a connection using %1.")
- .arg(lib->name()));
- }
-}
-
-ZConfLib::RunLoopStatus MainConnection::handleEvent()
-{
- qint64 now = QDateTime::currentMSecsSinceEpoch();
- qint64 nextEvent = now; // worth keeping a heap to quickly calculate this?
- foreach (ServiceBrowserPrivate *bAtt, m_browsers) {
- if (nextEvent < bAtt->delayDeletesUntil)
- nextEvent = bAtt->delayDeletesUntil;
- }
- if (nextEvent <= now)
- nextEvent = -1;
- else
- nextEvent -= now;
- maybeUpdateLists();
- ZConfLib::RunLoopStatus err = lib->processOneEvent(this, m_mainRef, nextEvent);
- if (err != ZConfLib::ProcessedOk && err != ZConfLib::ProcessedIdle) {
- qDebug() << "processOneEvent returned " << err;
- ++m_nErrs;
- } else {
- m_nErrs = 0;
- }
- return err;
-}
-
-void MainConnection::destroyConnection()
-{
- // multithreading issues if we support multiple cycles of createConnection/destroyConnection
- for (int i = m_browsers.count(); i-- != 0;){
- ServiceBrowserPrivate *bAtt = m_browsers[i];
- if (bAtt->browsing)
- bAtt->stopBrowsing();
- }
- if (m_mainRef != 0)
- lib->destroyConnection(&m_mainRef);
- m_mainRef = 0;
-}
-
-void MainConnection::handleEvents()
-{
- try {
- if (!m_status.testAndSetAcquire(Starting, Started)){
- appendError(ErrorMessage::WarningLevel, tr("Zeroconf, unexpected start status, aborting."));
- increaseStatusTo(Stopped);
- return;
- }
- m_nErrs = 0;
- createConnection();
- } catch(...) {
- mainThreadLock()->unlock();
- throw;
- }
- mainThreadLock()->unlock();
- increaseStatusTo(Running);
- while (status() < Stopping) {
- QMutexLocker l(mainThreadLock());
- if (m_nErrs > 10)
- increaseStatusTo(Stopping);
- switch (handleEvent()) {
- case ZConfLib::ProcessedOk :
- case ZConfLib::ProcessedIdle :
- break;
- case ZConfLib::ProcessedError :
- ++m_nErrs;
- break;
- case ZConfLib::ProcessedFailure :
- increaseStatusTo(Stopping);
- ++m_nErrs;
- break;
- case ZConfLib::ProcessedQuit :
- increaseStatusTo(Stopping);
- break;
- default:
- appendError(ErrorMessage::FailureLevel, tr("Zeroconf detected an unexpected return status of handleEvent."));
- increaseStatusTo(Stopping);
- break;
- }
- }
- destroyConnection();
- if (m_nErrs > 0){
- QString browsersNames = (m_browsers.isEmpty() ? QString() : m_browsers.at(0)->serviceType)
- + ((m_browsers.count() > 1) ? QString::fromLatin1(",...") : QString());
- if (isOk())
- appendError(ErrorMessage::FailureLevel,
- tr("Zeroconf for [%1] accumulated %n consecutive errors, aborting.", 0, m_nErrs)
- .arg(browsersNames));
- }
- increaseStatusTo(Stopped);
-}
-
-ZConfLib::ConnectionRef MainConnection::mainRef()
-{
- while (status() < Running){
- QThread::yieldCurrentThread();
- }
- return m_mainRef;
-}
-
-MainConnection::Status MainConnection::status()
-{
- return static_cast<MainConnection::Status>(m_status.load());
-}
-
-QList<ErrorMessage> MainConnection::errors()
-{
- QMutexLocker l(lock());
- return m_errors;
-}
-
-void MainConnection::appendError(ErrorMessage::SeverityLevel severity, const QString &msg)
-{
- QList<ServiceBrowserPrivate *> browsersAtt;
- QList<ErrorMessage> errs;
- {
- QMutexLocker l(lock());
- m_errors.append(ErrorMessage(severity, msg));
- errs = m_errors;
- browsersAtt = m_browsers;
- m_failed = severity == ErrorMessage::FailureLevel || m_failed;
- }
- foreach (ServiceBrowserPrivate *b, browsersAtt) {
- b->errorMessage(severity, msg);
- if (severity == ErrorMessage::FailureLevel)
- b->hadFailure(errs);
- }
-}
-
-void MainConnection::startupPhase(int progress, const QString &description)
-{
- QList<ServiceBrowserPrivate *> browsersAtt;
- {
- QMutexLocker l(lock());
- browsersAtt = m_browsers;
- }
- foreach (ServiceBrowserPrivate *b, browsersAtt)
- b->startupPhase(progress, description);
-}
-
-bool MainConnection::isOk()
-{
- return !m_failed;
-}
-
-// ----------------- ZConfLib impl -----------------
-
-bool ZConfLib::tryStartDaemon(ErrorMessage::ErrorLogger * /* logger */)
-{
- return false;
-}
-
-QString ZConfLib::name(){
- return QString::fromLatin1("ZeroConfLib@%1").arg(size_t(this), 0, 16);
-}
-
-ZConfLib::ZConfLib(ZConfLib::Ptr f) : fallbackLib(f), m_isOk(true), m_maxErrors(4)
-{ }
-
-ZConfLib::~ZConfLib()
-{ }
-
-bool ZConfLib::isOk()
-{
- return m_isOk;
-}
-
-QString ZConfLib::errorMsg()
-{
- return m_errorMsg;
-}
-
-void ZConfLib::setError(bool failure, const QString &eMsg)
-{
- m_errorMsg = eMsg;
- m_isOk = !failure;
-}
-
-int ZConfLib::maxErrors() const
-{
- return m_maxErrors;
-}
-
-int ZConfLib::nFallbacks() const
-{
- return (m_isOk ? ((m_maxErrors > 0) ? m_maxErrors : 1) : 0)
- + (fallbackLib ? fallbackLib->nFallbacks() : 0);
-}
-
-ZConfLib::RunLoopStatus ZConfLib::processOneEvent(MainConnection *mainConnection,
- ConnectionRef cRef, qint64 maxMsBlock)
-{
- if (maxMsBlock < 0) { // just block
- 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;
- fd_set readfds;
- struct timeval tv;
- int result;
- dns_sd_fd = (cRef ? refSockFD(cRef) : -1);
- if (dns_sd_fd < 0)
- return ProcessedError;
- nfds = dns_sd_fd + 1;
- FD_ZERO(&readfds);
- FD_SET(dns_sd_fd, &readfds);
-
- if (maxMsBlock > MAX_SEC_FOR_READ * static_cast<qint64>(1000)) {
- tv.tv_sec = MAX_SEC_FOR_READ;
- tv.tv_usec = 0;
- } else {
- 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);
- } else if (result == 0) {
- return ProcessedIdle;
- } else if (errno != EINTR) {
- if (DEBUG_ZEROCONF)
- qDebug() << "select() returned " << result << " errno " << errno
- << strerror(errno);
- return ProcessedError;
- }
- return ProcessedIdle; // change? should never happen anyway
-}
-
-}
-
-int ServiceBrowser::maxProgress() const
-{
- return zeroConfLibInstance()->nFallbacksTot() + 3;
-}
-
-// namespace Internal
-} // namespace ZeroConf