From 30a6beaec000d43ea6bf8f37d5c8d3615b56bbbe Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed Date: Mon, 14 May 2012 18:40:06 +0200 Subject: [PATCH] zeroconf: adding a signal to track initial startup * improving error messages * track startup Change-Id: Iba5a293b03b2d46facfbc7a9827d0d71eb7ba152 Reviewed-by: Christian Kandeler --- src/libs/zeroconf/avahiLib.cpp | 6 +- src/libs/zeroconf/dnsSdLib.cpp | 8 +- src/libs/zeroconf/embeddedLib.cpp | 41 +++++++++-- src/libs/zeroconf/servicebrowser.cpp | 106 ++++++++++++++++++++------- src/libs/zeroconf/servicebrowser.h | 7 ++ src/libs/zeroconf/servicebrowser_p.h | 9 ++- src/tools/mdnssd/PosixDaemon.c | 6 +- 7 files changed, 139 insertions(+), 44 deletions(-) diff --git a/src/libs/zeroconf/avahiLib.cpp b/src/libs/zeroconf/avahiLib.cpp index d84ea9726a3..bb4832c6458 100644 --- a/src/libs/zeroconf/avahiLib.cpp +++ b/src/libs/zeroconf/avahiLib.cpp @@ -184,7 +184,7 @@ public: } QString name(){ - return QString::fromLatin1("AvahiZeroConfLib@%1").arg(size_t(this), 0, 16); + return QString::fromLatin1("Avahi Library"); } // bool tryStartDaemon(); @@ -483,7 +483,7 @@ extern "C" void cAvahiClientReply (AvahiClient * /*s*/, AvahiClientState state, lib->setError(false, ZConfLib::tr("cAvahiClient, still connecting, no server available")); break; default: - lib->setError(true, ZConfLib::tr("Error: unexpected state %1 in cAvahiClientReply, ignoring it") + lib->setError(true, ZConfLib::tr("unexpected state %1 in cAvahiClientReply") .arg(state)); } } @@ -534,7 +534,7 @@ extern "C" void cAvahiBrowseReply( break; default: browser->mainConnection->lib->setError(true, ZConfLib::tr( - "Error: unexpected state %1 in cAvahiBrowseReply, ignoring it") + "unexpected state %1 in cAvahiBrowseReply") .arg(event)); } } diff --git a/src/libs/zeroconf/dnsSdLib.cpp b/src/libs/zeroconf/dnsSdLib.cpp index 5915ff36838..7a5899e690f 100644 --- a/src/libs/zeroconf/dnsSdLib.cpp +++ b/src/libs/zeroconf/dnsSdLib.cpp @@ -113,7 +113,7 @@ public: // dynamic linking if (!dnsSdLib.load()) { m_isOk = false; - m_errorMsg = tr("DnsSdZConfLib could not load native library"); + m_errorMsg = tr("could not load native library"); } m_refDeallocate = reinterpret_cast(dnsSdLib.resolve("DNSServiceRefDeallocate")); m_resolve = reinterpret_cast(dnsSdLib.resolve("DNSServiceResolve")); @@ -141,9 +141,9 @@ public: if (m_isOk && m_getAddrInfo == 0) { m_isOk = false; #ifdef Q_OS_LINUX - m_errorMsg = tr("DnsSdZConfLib skipping over avahi compatibility lib (or obsolete mdnsd)"); + m_errorMsg = tr("skipping over avahi compatibility lib (or obsolete mdnsd)"); #else - m_errorMsg = tr("*WARNING* DnsSdZConfLib detected an obsolete version of Apple Bonjour, either disable/uninstall it or upgrade it. Otherwise zeroconf will fail."); + m_errorMsg = tr("*WARNING* detected an obsolete version of Apple Bonjour, either disable/uninstall it or upgrade it, otherwise zeroconf will fail"); #endif } if (DEBUG_ZEROCONF){ @@ -164,7 +164,7 @@ public: } QString name(){ - return QString::fromLatin1("DnsSdZeroConfLib@%1").arg(size_t(this), 0, 16); + return QString::fromLatin1("Dns_sd (Apple Bonjour) Library"); } // bool tryStartDaemon(); diff --git a/src/libs/zeroconf/embeddedLib.cpp b/src/libs/zeroconf/embeddedLib.cpp index 6aef9f2c383..244e7c77fab 100644 --- a/src/libs/zeroconf/embeddedLib.cpp +++ b/src/libs/zeroconf/embeddedLib.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -82,10 +83,10 @@ public: QString name() { - return QString::fromLatin1("EmbeddedZeroConfLib@%1").arg(size_t(this), 0, 16); + return QString::fromLatin1("Embedded Dns_sd Library"); } - bool tryStartDaemon() + bool tryStartDaemon(ErrorMessage::ErrorLogger *logger) { if (!daemonPath.isEmpty()) { QFileInfo dPath(daemonPath); @@ -106,18 +107,46 @@ public: killall.waitForFinished(); } if (killAllFailed) { - this->setError(false,ZConfLib::tr("zeroconf failed to kill other daemons with '%1'").arg(cmd)); + if (logger) + logger->appendError(ErrorMessage::WarningLevel, + ZConfLib::tr("%1 failed to kill other daemons with '%2'.") + .arg(name()).arg(cmd)); if (DEBUG_ZEROCONF) qDebug() << name() << " had an error trying to kill other daemons with " << cmd; } - if (QProcess::startDetached(daemonPath)) { + QString daemonCmd = daemonPath; + QStringList daemonArgs; +#ifdef Q_OS_LINUX + if (QFile::exists("/tmp/mdnsd") && logger) + logger->appendError(ErrorMessage::WarningLevel, + ZConfLib::tr("%1 detected a file at /tmp/mdnsd, daemon startup will probably fail.") + .arg(name())); + QString logFile = QString::fromLatin1("/tmp/mdnssd.log"); + static int didFail = 0; + QFile oldLog(logFile); + if (didFail > 1 && oldLog.exists()) { + oldLog.open(QIODevice::ReadOnly); + if (logger) { + QByteArray logBA = oldLog.readAll(); + logger->appendError(ErrorMessage::NoteLevel, + ZConfLib::tr("%1: log of previous daemon run is: '%2'.\n") + .arg(name()) + .arg(QString::fromAscii(logBA.constData(), logBA.size()))); + qDebug()< 1) + daemonArgs << QString::fromLatin1("-debug"); +#endif + if (QProcess::startDetached(daemonCmd, daemonArgs)) { QThread::yieldCurrentThread(); // sleep a bit? if (DEBUG_ZEROCONF) - qDebug() << name() << " started " << daemonPath; + qDebug() << name() << " started " << daemonCmd << daemonArgs; return true; } else { - this->setError(true, ZConfLib::tr("%1 failed starting embedded daemon at %2") + this->setError(true, ZConfLib::tr("%1 failed starting embedded daemon at %2.") .arg(name()).arg(daemonPath)); } } diff --git a/src/libs/zeroconf/servicebrowser.cpp b/src/libs/zeroconf/servicebrowser.cpp index 6e73b0a1cd5..dc0657bae4e 100644 --- a/src/libs/zeroconf/servicebrowser.cpp +++ b/src/libs/zeroconf/servicebrowser.cpp @@ -135,10 +135,12 @@ public: 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; }; @@ -163,6 +165,8 @@ ZeroConfLib::ZeroConfLib(): m_lock(QMutex::Recursive), qRegisterMetaType("ZeroConf::ErrorMessage::SeverityLevel"); qRegisterMetaType("ZeroConf::ErrorMessage"); qRegisterMetaType >("QList"); + m_nFallbacksTot = (m_defaultLib ? m_defaultLib->nFallbacks() : 0); + } ZConfLib::Ptr ZeroConfLib::defaultLib(){ @@ -196,6 +200,14 @@ void ZeroConfLib::setDefaultLib(LibUsage usage, const QString &avahiLibName, 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 @@ -1468,9 +1480,12 @@ void ServiceBrowserPrivate::startBrowsing(quint32 interfaceIndex) this->interfaceIndex = interfaceIndex; if (failed || browsing) return; - if (mainConnection.isNull()) - mainConnection = MainConnectionPtr(new MainConnection()); - mainConnection->addBrowser(this); + if (mainConnection.isNull()) { + startupPhase(1, q->tr("Starting Zeroconf Browsing")); + mainConnection = MainConnectionPtr(new MainConnection(this)); + } else { + mainConnection->addBrowser(this); + } } bool ServiceBrowserPrivate::internalStartBrowsing() @@ -1568,6 +1583,13 @@ 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) { @@ -1612,13 +1634,15 @@ void MainConnection::stop(bool wait) m_thread->wait(); } -MainConnection::MainConnection(): +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()){ - qDebug() << "could not load a valid library for ZeroConf::MainConnection, failing"; + appendError(ErrorMessage::FailureLevel, tr("Zeroconf could not load a valid library, failing.")); } else { m_thread = new ConnectionThread(*this); m_mainThreadLock.lock(); @@ -1718,28 +1742,28 @@ void MainConnection::maybeUpdateLists() void MainConnection::gotoValidLib(){ while (lib){ if (lib->isOk()) break; - appendError(ErrorMessage::WarningLevel, tr("MainConnection giving up on non Ok lib %1 (%2)") + 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("MainConnection has no valid library, aborting connection")); + appendError(ErrorMessage::FailureLevel, tr("Zeroconf has no valid library, aborting connection.")); increaseStatusTo(Stopping); } } void MainConnection::abortLib(){ if (!lib){ - appendError(ErrorMessage::FailureLevel, tr("MainConnection has no valid library, aborting connection")); + appendError(ErrorMessage::FailureLevel, tr("Zeroconf has no valid library, aborting connection.")); increaseStatusTo(Stopping); } else if (lib->fallbackLib){ - appendError(ErrorMessage::WarningLevel, tr("MainConnection giving up on lib %1, switching to lib %2") + 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("MainConnection giving up on lib %1, no fallback provided, aborting connection") + appendError(ErrorMessage::FailureLevel, tr("Zeroconf giving up on %1, no fallback provided, aborting connection.") .arg(lib->name())); increaseStatusTo(Stopping); } @@ -1753,16 +1777,18 @@ void MainConnection::createConnection() 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("MainConnection using lib %1 failed the initialization of mainRef with error %2") + 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->maxErrors() || !lib->isOk()) + if (m_nErrs > lib->nFallbacks() || !lib->isOk()) abortLib(); } else { QList waitingBrowsers; @@ -1780,29 +1806,31 @@ void MainConnection::createConnection() break; } } else if (err == kDNSServiceErr_ServiceNotRunning) { - appendError(ErrorMessage::WarningLevel, tr("MainConnection using lib %1 failed because no daemon is running") + appendError(ErrorMessage::WarningLevel, tr("Zeroconf using %1 failed because no daemon is running.") .arg(lib->name())); - if (m_nErrs > lib->maxErrors()/2 || !lib->isOk()) { + ++m_nErrs; + if (m_nErrs > lib->maxErrors() || !lib->isOk()) { abortLib(); - } else if (lib->tryStartDaemon()) { - ++m_nErrs; - appendError(ErrorMessage::WarningLevel, tr("MainConnection using lib %1 daemon starting seem successful, continuing") + } else if (lib->tryStartDaemon(this)) { + appendError(ErrorMessage::WarningLevel, tr("Zeroconf using %1 daemon starting seem successful, continuing.") .arg(lib->name())); } else { - appendError(ErrorMessage::WarningLevel, tr("MainConnection using lib %1 failed because no daemon is running") + appendError(ErrorMessage::WarningLevel, tr("Zeroconf using %1 failed because no daemon is running.") .arg(lib->name())); abortLib(); } } else { - appendError(ErrorMessage::WarningLevel, tr("MainConnection using lib %1 failed getProperty call with error %2") + appendError(ErrorMessage::WarningLevel, tr("Zeroconf using %1 failed getProperty call with error %2.") .arg(lib->name()).arg(err)); abortLib(); } } - if (status() < Stopping) + if (status() < Stopping) { + startupPhase(zeroConfLibInstance()->nFallbacksTot() + 3, tr("Succeded using %1.").arg(lib->name())); appendError(ErrorMessage::NoteLevel, - tr("MainConnection could successfully create a connection using lib %1") + tr("MainConnection could successfully create a connection using %1.") .arg(lib->name())); + } } ZConfLib::RunLoopStatus MainConnection::handleEvent() @@ -1845,7 +1873,7 @@ void MainConnection::handleEvents() { try { if (!m_status.testAndSetAcquire(Starting, Started)){ - appendError(ErrorMessage::WarningLevel, tr("MainConnection::handleEvents called with m_status != Starting, aborting")); + appendError(ErrorMessage::WarningLevel, tr("Zeroconf, unexpected start status, aborting.")); increaseStatusTo(Stopped); return; } @@ -1876,7 +1904,7 @@ void MainConnection::handleEvents() increaseStatusTo(Stopping); break; default: - appendError(ErrorMessage::FailureLevel, tr("MainConnection::handleEvents unexpected return status of handleEvent")); + appendError(ErrorMessage::FailureLevel, tr("Zeroconf detected an unexpected return status of handleEvent.")); increaseStatusTo(Stopping); break; } @@ -1886,7 +1914,7 @@ void MainConnection::handleEvents() QString browsersNames = (m_browsers.isEmpty() ? QString() : m_browsers.at(0)->serviceType) + ((m_browsers.count() > 1) ? QString::fromLatin1(",...") : QString()); if (isOk()) - appendError(ErrorMessage::FailureLevel, tr("MainConnection for [%1] accumulated %2 consecutive errors, aborting") + appendError(ErrorMessage::FailureLevel, tr("Zeroconf for [%1] accumulated %2 consecutive errors, aborting.") .arg(browsersNames).arg(m_nErrs)); } increaseStatusTo(Stopped); @@ -1934,6 +1962,17 @@ void MainConnection::appendError(ErrorMessage::SeverityLevel severity, const QSt } } +void MainConnection::startupPhase(int progress, const QString &description) +{ + QList browsersAtt; + { + QMutexLocker l(lock()); + browsersAtt = m_browsers; + } + foreach (ServiceBrowserPrivate *b, browsersAtt) + b->startupPhase(progress, description); +} + bool MainConnection::isOk() { return !m_failed; @@ -1941,7 +1980,7 @@ bool MainConnection::isOk() // ----------------- ZConfLib impl ----------------- -bool ZConfLib::tryStartDaemon() +bool ZConfLib::tryStartDaemon(ErrorMessage::ErrorLogger * /* logger */) { return false; } @@ -1950,7 +1989,7 @@ 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(8) +ZConfLib::ZConfLib(ZConfLib::Ptr f) : fallbackLib(f), m_isOk(true), m_maxErrors(4) { } ZConfLib::~ZConfLib() @@ -1977,6 +2016,12 @@ 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) { @@ -2023,5 +2068,12 @@ ZConfLib::RunLoopStatus ZConfLib::processOneEvent(MainConnection *mainConnection return ProcessedIdle; // change? should never happen anyway } -} // namespace Internal +} + +int ServiceBrowser::maxProgress() const +{ + return zeroConfLibInstance()->nFallbacksTot() + 3; +} + +// namespace Internal } // namespace ZeroConf diff --git a/src/libs/zeroconf/servicebrowser.h b/src/libs/zeroconf/servicebrowser.h index 901089c3ca0..36667a4f342 100644 --- a/src/libs/zeroconf/servicebrowser.h +++ b/src/libs/zeroconf/servicebrowser.h @@ -73,6 +73,11 @@ public: SeverityLevel severity; QString msg; + + class ErrorLogger{ + public: + virtual void appendError(ErrorMessage::SeverityLevel severity, const QString& msg) = 0; + }; }; ZEROCONFSHARED_EXPORT QDebug operator<<(QDebug dbg, const ErrorMessage &eMsg); @@ -142,6 +147,7 @@ public: void stopBrowsing(); bool isBrowsing() const; bool didFail() const; + int maxProgress() const; const QString& serviceType() const; const QString& domain() const; @@ -163,6 +169,7 @@ signals: void serviceRemoved(const ZeroConf::Service::ConstPtr &service, ZeroConf::ServiceBrowser *browser); void servicesUpdated(ZeroConf::ServiceBrowser *browser); + void startupPhase(int progress, const QString &description, ZeroConf::ServiceBrowser *browser); void errorMessage(ZeroConf::ErrorMessage::SeverityLevel severity, const QString &msg, ZeroConf::ServiceBrowser *browser); void hadFailure(const QList &messages, ZeroConf::ServiceBrowser *browser); void startedBrowsing(ZeroConf::ServiceBrowser *browser); diff --git a/src/libs/zeroconf/servicebrowser_p.h b/src/libs/zeroconf/servicebrowser_p.h index d2c1624927c..bf69aba00c0 100644 --- a/src/libs/zeroconf/servicebrowser_p.h +++ b/src/libs/zeroconf/servicebrowser_p.h @@ -86,7 +86,7 @@ public: virtual QString name(); - virtual bool tryStartDaemon(); + virtual bool tryStartDaemon(ErrorMessage::ErrorLogger *logger = 0); virtual void refDeallocate(DNSServiceRef sdRef) = 0; virtual void browserDeallocate(BrowserRef *sdRef) = 0; @@ -120,6 +120,7 @@ public: bool isOk(); QString errorMsg(); void setError(bool failure, const QString &eMsg); + int nFallbacks() const; int maxErrors() const; static Ptr createEmbeddedLib(const QString &daemonPath, const Ptr &fallback = Ptr(0)); @@ -215,7 +216,7 @@ private: class ConnectionThread; -class MainConnection { +class MainConnection : private ErrorMessage::ErrorLogger { Q_DECLARE_TR_FUNCTIONS(ZeroConf) public: enum RequestFlowStatus { @@ -234,7 +235,7 @@ public: }; ZConfLib::Ptr lib; - MainConnection(); + MainConnection(ServiceBrowserPrivate *initialBrowser = 0); ~MainConnection(); QMutex *lock(); QMutex *mainThreadLock(); @@ -257,6 +258,7 @@ public: QList errors(); bool isOk(); + void startupPhase(int progress, const QString &msg); private: void appendError(ErrorMessage::SeverityLevel severity, const QString &msg); @@ -321,6 +323,7 @@ public: void serviceAdded(const Service::ConstPtr &service, ServiceBrowser *browser); void serviceRemoved(const Service::ConstPtr &service, ServiceBrowser *browser); void servicesUpdated(ServiceBrowser *browser); + void startupPhase(int progress, const QString &description); void errorMessage(ErrorMessage::SeverityLevel severity, const QString &msg); void hadFailure(const QList &msgs); void startedBrowsing(); diff --git a/src/tools/mdnssd/PosixDaemon.c b/src/tools/mdnssd/PosixDaemon.c index 4748fa53df1..d56ef948e04 100644 --- a/src/tools/mdnssd/PosixDaemon.c +++ b/src/tools/mdnssd/PosixDaemon.c @@ -105,7 +105,11 @@ mDNSlocal void ParseCmdLinArgs(int argc, char **argv) { if (argc > 1) { - if (0 == strcmp(argv[1], "-debug")) mDNS_DebugMode = mDNStrue; + if (0 == strcmp(argv[1], "-debug")) { + mDNS_DebugMode = mDNStrue; + stderr = fopen("/tmp/mdnssd.log", "w"); + stdout = stderr; + } else printf("Usage: %s [-debug]\n", argv[0]); }