zeroconf: adding a signal to track initial startup

* improving error messages
* track startup
Change-Id: Iba5a293b03b2d46facfbc7a9827d0d71eb7ba152
Reviewed-by: Christian Kandeler <christian.kandeler@nokia.com>
This commit is contained in:
Fawzi Mohamed
2012-05-14 18:40:06 +02:00
parent e58f203e4c
commit 30a6beaec0
7 changed files with 139 additions and 44 deletions

View File

@@ -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));
}
}

View File

@@ -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<RefDeallocatePtr>(dnsSdLib.resolve("DNSServiceRefDeallocate"));
m_resolve = reinterpret_cast<ResolvePtr>(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();

View File

@@ -36,6 +36,7 @@
#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QString>
#include <QStringList>
@@ -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()<<logBA.size()<<oldLog.error()<<oldLog.errorString();
}
oldLog.close();
}
if (++didFail > 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));
}
}

View File

@@ -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>("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(){
@@ -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<ServiceBrowserPrivate *> 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<ServiceBrowserPrivate *> 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

View File

@@ -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<ZeroConf::ErrorMessage> &messages, ZeroConf::ServiceBrowser *browser);
void startedBrowsing(ZeroConf::ServiceBrowser *browser);

View File

@@ -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<ErrorMessage> 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<ErrorMessage> &msgs);
void startedBrowsing();

View File

@@ -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]);
}