forked from qt-creator/qt-creator
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:
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
1518
src/libs/zeroconf/embed/CommonServices.h
Normal file
1518
src/libs/zeroconf/embed/CommonServices.h
Normal file
File diff suppressed because it is too large
Load Diff
3075
src/libs/zeroconf/embed/DebugServices.c
Normal file
3075
src/libs/zeroconf/embed/DebugServices.c
Normal file
File diff suppressed because it is too large
Load Diff
1607
src/libs/zeroconf/embed/DebugServices.h
Normal file
1607
src/libs/zeroconf/embed/DebugServices.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -40,17 +40,16 @@ 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>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define sockaddr_mdns sockaddr_in
|
||||
#define AF_MDNS AF_INET
|
||||
@@ -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);
|
||||
}
|
||||
|
@@ -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));
|
||||
}
|
||||
|
@@ -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,17 +1350,20 @@ 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();
|
||||
{
|
||||
QMutexLocker l(mainConnection->lock());
|
||||
activeServices = nextActiveServices;
|
||||
hasServicesChanges = hasServicesChanges || g->enactServiceChange();
|
||||
if (hasServicesChanges) {
|
||||
{
|
||||
QMutexLocker l(mainConnection->lock());
|
||||
activeServices = nextActiveServices;
|
||||
}
|
||||
emit q->servicesUpdated(q);
|
||||
}
|
||||
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->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,45 +1931,50 @@ 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 {
|
||||
// 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);
|
||||
}
|
||||
result = select(nfds, &readfds, (fd_set *)NULL, (fd_set *)NULL, &tv);
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
|
@@ -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 {
|
||||
|
Reference in New Issue
Block a user