src/dbus/qdbusintegrator.cpp
branchRCL_3
changeset 4 3b1da2848fc7
parent 3 41300fa6a67c
child 5 d3bac044e0f0
equal deleted inserted replaced
3:41300fa6a67c 4:3b1da2848fc7
     1 /****************************************************************************
     1 /****************************************************************************
     2 **
     2 **
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     4 ** All rights reserved.
     4 ** All rights reserved.
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     6 **
     6 **
     7 ** This file is part of the QtDBus module of the Qt Toolkit.
     7 ** This file is part of the QtDBus module of the Qt Toolkit.
     8 **
     8 **
   388     server_d->serverConnection(retval);
   388     server_d->serverConnection(retval);
   389 }
   389 }
   390 
   390 
   391 } // extern "C"
   391 } // extern "C"
   392 
   392 
   393 static QByteArray buildMatchRule(const QString &service, const QString & /*owner*/,
   393 static QByteArray buildMatchRule(const QString &service,
   394                                  const QString &objectPath, const QString &interface,
   394                                  const QString &objectPath, const QString &interface,
   395                                  const QString &member, const QStringList &argMatch, const QString & /*signature*/)
   395                                  const QString &member, const QStringList &argMatch, const QString & /*signature*/)
   396 {
   396 {
   397     QString result = QLatin1String("type='signal',");
   397     QString result = QLatin1String("type='signal',");
   398     QString keyValue = QLatin1String("%1='%2',");
   398     QString keyValue = QLatin1String("%1='%2',");
   521     QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
   521     QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
   522     if (d->mode == QDBusConnectionPrivate::InvalidMode)
   522     if (d->mode == QDBusConnectionPrivate::InvalidMode)
   523         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
   523         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
   524 
   524 
   525     QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(message);
   525     QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(message);
   526     qDBusDebug() << QThread::currentThread() << "got message:" << amsg;
   526     qDBusDebug() << d << "got message:" << amsg;
   527 
   527 
   528     return d->handleMessage(amsg) ?
   528     return d->handleMessage(amsg) ?
   529         DBUS_HANDLER_RESULT_HANDLED :
   529         DBUS_HANDLER_RESULT_HANDLED :
   530         DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
   530         DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
   531 }
   531 }
   911     // do we create a reply? Only if the caller is waiting for a reply and one hasn't been sent
   911     // do we create a reply? Only if the caller is waiting for a reply and one hasn't been sent
   912     // yet.
   912     // yet.
   913     if (msg.isReplyRequired() && !msg.isDelayedReply()) {
   913     if (msg.isReplyRequired() && !msg.isDelayedReply()) {
   914         if (!fail) {
   914         if (!fail) {
   915             // normal reply
   915             // normal reply
   916             qDBusDebug() << QThread::currentThread() << "Automatically sending reply:" << outputArgs;
   916             qDBusDebug() << this << "Automatically sending reply:" << outputArgs;
   917             send(msg.createReply(outputArgs));
   917             send(msg.createReply(outputArgs));
   918         } else {
   918         } else {
   919             // generate internal error
   919             // generate internal error
   920             qWarning("Internal error: Failed to deliver message");
   920             qWarning("Internal error: Failed to deliver message");
   921             send(msg.createErrorReply(QDBusError::InternalError,
   921             send(msg.createErrorReply(QDBusError::InternalError,
   945 #endif
   945 #endif
   946 
   946 
   947     QDBusMetaTypeId::init();
   947     QDBusMetaTypeId::init();
   948 
   948 
   949     rootNode.flags = 0;
   949     rootNode.flags = 0;
   950     watchedServiceNames[QLatin1String(DBUS_SERVICE_DBUS)] = 1;
       
   951 }
   950 }
   952 
   951 
   953 QDBusConnectionPrivate::~QDBusConnectionPrivate()
   952 QDBusConnectionPrivate::~QDBusConnectionPrivate()
   954 {
   953 {
   955     if (thread() && thread() != QThread::currentThread())
   954     if (thread() && thread() != QThread::currentThread())
  1177 void QDBusConnectionPrivate::_q_serviceOwnerChanged(const QString &name,
  1176 void QDBusConnectionPrivate::_q_serviceOwnerChanged(const QString &name,
  1178                                                     const QString &oldOwner, const QString &newOwner)
  1177                                                     const QString &oldOwner, const QString &newOwner)
  1179 {
  1178 {
  1180     Q_UNUSED(oldOwner);
  1179     Q_UNUSED(oldOwner);
  1181     QDBusWriteLocker locker(UpdateSignalHookOwnerAction, this);
  1180     QDBusWriteLocker locker(UpdateSignalHookOwnerAction, this);
  1182     QMutableHashIterator<QString, SignalHook> it(signalHooks);
  1181     WatchedServicesHash::Iterator it = watchedServices.find(name);
  1183     it.toFront();
  1182     if (it == watchedServices.end())
  1184     while (it.hasNext())
  1183         return;
  1185         if (it.next().value().service == name)
  1184     if (oldOwner != it->owner)
  1186             it.value().owner = newOwner;
  1185         qWarning("QDBusConnection: name '%s' had owner '%s' but we thought it was '%s'",
       
  1186                  qPrintable(name), qPrintable(oldOwner), qPrintable(it->owner));
       
  1187 
       
  1188     qDBusDebug() << this << "Updating name" << name << "from" << oldOwner << "to" << newOwner;
       
  1189     it->owner = newOwner;
  1187 }
  1190 }
  1188 
  1191 
  1189 int QDBusConnectionPrivate::findSlot(QObject* obj, const QByteArray &normalizedName,
  1192 int QDBusConnectionPrivate::findSlot(QObject* obj, const QByteArray &normalizedName,
  1190                                      QList<int> &params)
  1193                                      QList<int> &params)
  1191 {
  1194 {
  1199 
  1202 
  1200     return midx;
  1203     return midx;
  1201 }
  1204 }
  1202 
  1205 
  1203 bool QDBusConnectionPrivate::prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key,
  1206 bool QDBusConnectionPrivate::prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key,
  1204                                          const QString &service, const QString &owner,
  1207                                          const QString &service,
  1205                                          const QString &path, const QString &interface, const QString &name,
  1208                                          const QString &path, const QString &interface, const QString &name,
  1206                                          const QStringList &argMatch,
  1209                                          const QStringList &argMatch,
  1207                                          QObject *receiver, const char *signal, int minMIdx,
  1210                                          QObject *receiver, const char *signal, int minMIdx,
  1208                                          bool buildSignature)
  1211                                          bool buildSignature)
  1209 {
  1212 {
  1218         {}
  1221         {}
  1219         return false;
  1222         return false;
  1220     }
  1223     }
  1221 
  1224 
  1222     hook.service = service;
  1225     hook.service = service;
  1223     hook.owner = owner; // we don't care if the service has an owner yet
       
  1224     hook.path = path;
  1226     hook.path = path;
  1225     hook.obj = receiver;
  1227     hook.obj = receiver;
  1226     hook.argumentMatch = argMatch;
  1228     hook.argumentMatch = argMatch;
  1227 
  1229 
  1228     // build the D-Bus signal name and signature
  1230     // build the D-Bus signal name and signature
  1243         for (int i = 1; i < hook.params.count(); ++i)
  1245         for (int i = 1; i < hook.params.count(); ++i)
  1244             if (hook.params.at(i) != QDBusMetaTypeId::message)
  1246             if (hook.params.at(i) != QDBusMetaTypeId::message)
  1245                 hook.signature += QLatin1String( QDBusMetaType::typeToSignature( hook.params.at(i) ) );
  1247                 hook.signature += QLatin1String( QDBusMetaType::typeToSignature( hook.params.at(i) ) );
  1246     }
  1248     }
  1247 
  1249 
  1248     hook.matchRule = buildMatchRule(service, owner, path, interface, mname, argMatch, hook.signature);
  1250     hook.matchRule = buildMatchRule(service, path, interface, mname, argMatch, hook.signature);
  1249     return true;                // connect to this signal
  1251     return true;                // connect to this signal
  1250 }
  1252 }
  1251 
  1253 
  1252 void QDBusConnectionPrivate::sendError(const QDBusMessage &msg, QDBusError::ErrorType code)
  1254 void QDBusConnectionPrivate::sendError(const QDBusMessage &msg, QDBusError::ErrorType code)
  1253 {
  1255 {
  1486     SignalHookHash::const_iterator end = signalHooks.constEnd();
  1488     SignalHookHash::const_iterator end = signalHooks.constEnd();
  1487     //qDebug("looking for: %s", path.toLocal8Bit().constData());
  1489     //qDebug("looking for: %s", path.toLocal8Bit().constData());
  1488     //qDBusDebug() << signalHooks.keys();
  1490     //qDBusDebug() << signalHooks.keys();
  1489     for ( ; it != end && it.key() == key; ++it) {
  1491     for ( ; it != end && it.key() == key; ++it) {
  1490         const SignalHook &hook = it.value();
  1492         const SignalHook &hook = it.value();
  1491         if (!hook.owner.isNull() && hook.owner != msg.service())
  1493         if (!hook.service.isEmpty()) {
  1492             continue;
  1494             const QString owner =
       
  1495                     shouldWatchService(hook.service) ?
       
  1496                     watchedServices.value(hook.service).owner :
       
  1497                     hook.service;
       
  1498             if (owner != msg.service())
       
  1499                 continue;
       
  1500         }
  1493         if (!hook.path.isEmpty() && hook.path != msg.path())
  1501         if (!hook.path.isEmpty() && hook.path != msg.path())
  1494             continue;
  1502             continue;
  1495         if (!hook.signature.isEmpty() && hook.signature != msg.signature())
  1503         if (!hook.signature.isEmpty() && hook.signature != msg.signature())
  1496             continue;
  1504             continue;
  1497         if (hook.signature.isEmpty() && !hook.signature.isNull() && !msg.signature().isEmpty())
  1505         if (hook.signature.isEmpty() && !hook.signature.isNull() && !msg.signature().isEmpty())
  1650     } else {
  1658     } else {
  1651         qWarning("QDBusConnectionPrivate::setConnection: Unable to get base service");
  1659         qWarning("QDBusConnectionPrivate::setConnection: Unable to get base service");
  1652     }
  1660     }
  1653 
  1661 
  1654     QString busService = QLatin1String(DBUS_SERVICE_DBUS);
  1662     QString busService = QLatin1String(DBUS_SERVICE_DBUS);
  1655     connectSignal(busService, QString(), QString(), QString(), QLatin1String("NameAcquired"), QStringList(), QString(),
  1663     WatchedServicesHash::mapped_type &bus = watchedServices[busService];
       
  1664     bus.refcount = 1;
       
  1665     bus.owner = getNameOwnerNoCache(busService);
       
  1666     connectSignal(busService, QString(), QString(), QLatin1String("NameAcquired"), QStringList(), QString(),
  1656                   this, SLOT(registerService(QString)));
  1667                   this, SLOT(registerService(QString)));
  1657     connectSignal(busService, QString(), QString(), QString(), QLatin1String("NameLost"), QStringList(), QString(),
  1668     connectSignal(busService, QString(), QString(), QLatin1String("NameLost"), QStringList(), QString(),
  1658                   this, SLOT(unregisterService(QString)));
  1669                   this, SLOT(unregisterService(QString)));
  1659 
  1670 
  1660 
  1671 
  1661     q_dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0);
  1672     q_dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0);
  1662 
  1673 
  1663     //qDebug("base service: %s", service);
  1674     qDBusDebug() << this << ": connected successfully";
  1664 
  1675 
  1665     // schedule a dispatch:
  1676     // schedule a dispatch:
  1666     QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
  1677     QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
  1667 }
  1678 }
  1668 
  1679 
  1693         // decode the message
  1704         // decode the message
  1694         DBusMessage *reply = q_dbus_pending_call_steal_reply(call->pending);
  1705         DBusMessage *reply = q_dbus_pending_call_steal_reply(call->pending);
  1695         msg = QDBusMessagePrivate::fromDBusMessage(reply);
  1706         msg = QDBusMessagePrivate::fromDBusMessage(reply);
  1696         q_dbus_message_unref(reply);
  1707         q_dbus_message_unref(reply);
  1697     }
  1708     }
  1698     qDBusDebug() << QThread::currentThread() << "got message reply (async):" << msg;
  1709     qDBusDebug() << connection << "got message reply (async):" << msg;
  1699 
  1710 
  1700     // Check if the reply has the expected signature
  1711     // Check if the reply has the expected signature
  1701     call->checkReceivedSignature();
  1712     call->checkReceivedSignature();
  1702 
  1713 
  1703     if (!call->receiver.isNull() && call->methodIdx != -1 && msg.type() == QDBusMessage::ReplyMessage) {
  1714     if (!call->receiver.isNull() && call->methodIdx != -1 && msg.type() == QDBusMessage::ReplyMessage) {
  1761         return 0;
  1772         return 0;
  1762     }
  1773     }
  1763 
  1774 
  1764     q_dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything
  1775     q_dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything
  1765 
  1776 
  1766     qDBusDebug() << QThread::currentThread() << "sending message (no reply):" << message;
  1777     qDBusDebug() << this << "sending message (no reply):" << message;
  1767     checkThread();
  1778     checkThread();
  1768     bool isOk = q_dbus_connection_send(connection, msg, 0);
  1779     bool isOk = q_dbus_connection_send(connection, msg, 0);
  1769     int serial = 0;
  1780     int serial = 0;
  1770     if (isOk)
  1781     if (isOk)
  1771         serial = q_dbus_message_get_serial(msg);
  1782         serial = q_dbus_message_get_serial(msg);
  1793                      qPrintable(err.message()));
  1804                      qPrintable(err.message()));
  1794             lastError = err;
  1805             lastError = err;
  1795             return QDBusMessage::createError(err);
  1806             return QDBusMessage::createError(err);
  1796         }
  1807         }
  1797 
  1808 
  1798         qDBusDebug() << QThread::currentThread() << "sending message (blocking):" << message;
  1809         qDBusDebug() << this << "sending message (blocking):" << message;
  1799         QDBusErrorInternal error;
  1810         QDBusErrorInternal error;
  1800         DBusMessage *reply = q_dbus_connection_send_with_reply_and_block(connection, msg, timeout, error);
  1811         DBusMessage *reply = q_dbus_connection_send_with_reply_and_block(connection, msg, timeout, error);
  1801 
  1812 
  1802         q_dbus_message_unref(msg);
  1813         q_dbus_message_unref(msg);
  1803 
  1814 
  1806             return QDBusMessage::createError(err);
  1817             return QDBusMessage::createError(err);
  1807         }
  1818         }
  1808 
  1819 
  1809         QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(reply);
  1820         QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(reply);
  1810         q_dbus_message_unref(reply);
  1821         q_dbus_message_unref(reply);
  1811         qDBusDebug() << QThread::currentThread() << "got message reply (blocking):" << amsg;
  1822         qDBusDebug() << this << "got message reply (blocking):" << amsg;
  1812 
  1823 
  1813         return amsg;
  1824         return amsg;
  1814     } else { // use the event loop
  1825     } else { // use the event loop
  1815         QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, timeout);
  1826         QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, timeout);
  1816         Q_ASSERT(pcall);
  1827         Q_ASSERT(pcall);
  1817 
  1828 
  1818         if (pcall->replyMessage.type() != QDBusMessage::InvalidMessage) {
  1829         if (pcall->replyMessage.type() == QDBusMessage::InvalidMessage) {
  1819             pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
  1830             pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
  1820             QEventLoop loop;
  1831             QEventLoop loop;
  1821             loop.connect(pcall->watcherHelper, SIGNAL(reply(QDBusMessage)), SLOT(quit()));
  1832             loop.connect(pcall->watcherHelper, SIGNAL(reply(QDBusMessage)), SLOT(quit()));
  1822             loop.connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), SLOT(quit()));
  1833             loop.connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), SLOT(quit()));
  1823 
  1834 
  1833     }
  1844     }
  1834 }
  1845 }
  1835 
  1846 
  1836 QDBusMessage QDBusConnectionPrivate::sendWithReplyLocal(const QDBusMessage &message)
  1847 QDBusMessage QDBusConnectionPrivate::sendWithReplyLocal(const QDBusMessage &message)
  1837 {
  1848 {
  1838     qDBusDebug() << QThread::currentThread() << "sending message via local-loop:" << message;
  1849     qDBusDebug() << this << "sending message via local-loop:" << message;
  1839 
  1850 
  1840     QDBusMessage localCallMsg = QDBusMessagePrivate::makeLocal(*this, message);
  1851     QDBusMessage localCallMsg = QDBusMessagePrivate::makeLocal(*this, message);
  1841     bool handled = handleMessage(localCallMsg);
  1852     bool handled = handleMessage(localCallMsg);
  1842 
  1853 
  1843     if (!handled) {
  1854     if (!handled) {
  1860             QDBusError(QDBusError::InternalError,
  1871             QDBusError(QDBusError::InternalError,
  1861                        QLatin1String("local-loop message cannot have delayed replies")));
  1872                        QLatin1String("local-loop message cannot have delayed replies")));
  1862     }
  1873     }
  1863 
  1874 
  1864     // there is a reply
  1875     // there is a reply
  1865     qDBusDebug() << QThread::currentThread() << "got message via local-loop:" << localReplyMsg;
  1876     qDBusDebug() << this << "got message via local-loop:" << localReplyMsg;
  1866     return localReplyMsg;
  1877     return localReplyMsg;
  1867 }
  1878 }
  1868 
  1879 
  1869 QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message,
  1880 QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message,
  1870                                                                     int timeout)
  1881                                                                     int timeout)
  1894         pcall->replyMessage = QDBusMessage::createError(error);
  1905         pcall->replyMessage = QDBusMessage::createError(error);
  1895         lastError = error;
  1906         lastError = error;
  1896         return pcall;
  1907         return pcall;
  1897     }
  1908     }
  1898 
  1909 
  1899     qDBusDebug() << QThread::currentThread() << "sending message (async):" << message;
  1910     qDBusDebug() << this << "sending message (async):" << message;
  1900     DBusPendingCall *pending = 0;
  1911     DBusPendingCall *pending = 0;
  1901 
  1912 
  1902     QDBusDispatchLocker locker(SendWithReplyAsyncAction, this);
  1913     QDBusDispatchLocker locker(SendWithReplyAsyncAction, this);
  1903     if (q_dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
  1914     if (q_dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
  1904         if (pending) {
  1915         if (pending) {
  1966     }
  1977     }
  1967 
  1978 
  1968     return 1;
  1979     return 1;
  1969 }
  1980 }
  1970 
  1981 
  1971 bool QDBusConnectionPrivate::connectSignal(const QString &service, const QString &owner,
  1982 bool QDBusConnectionPrivate::connectSignal(const QString &service,
  1972                                            const QString &path, const QString &interface, const QString &name,
  1983                                            const QString &path, const QString &interface, const QString &name,
  1973                                            const QStringList &argumentMatch, const QString &signature,
  1984                                            const QStringList &argumentMatch, const QString &signature,
  1974                                            QObject *receiver, const char *slot)
  1985                                            QObject *receiver, const char *slot)
  1975 {
  1986 {
  1976     // check the slot
  1987     // check the slot
  1979     QString name2 = name;
  1990     QString name2 = name;
  1980     if (name2.isNull())
  1991     if (name2.isNull())
  1981         name2.detach();
  1992         name2.detach();
  1982 
  1993 
  1983     hook.signature = signature;
  1994     hook.signature = signature;
  1984     if (!prepareHook(hook, key, service, owner, path, interface, name, argumentMatch, receiver, slot, 0, false))
  1995     if (!prepareHook(hook, key, service, path, interface, name, argumentMatch, receiver, slot, 0, false))
  1985         return false;           // don't connect
  1996         return false;           // don't connect
  1986 
  1997 
  1987     // avoid duplicating:
  1998     // avoid duplicating:
  1988     QDBusConnectionPrivate::SignalHookHash::ConstIterator it = signalHooks.find(key);
  1999     QDBusConnectionPrivate::SignalHookHash::ConstIterator it = signalHooks.find(key);
  1989     QDBusConnectionPrivate::SignalHookHash::ConstIterator end = signalHooks.constEnd();
  2000     QDBusConnectionPrivate::SignalHookHash::ConstIterator end = signalHooks.constEnd();
  1990     for ( ; it != end && it.key() == key; ++it) {
  2001     for ( ; it != end && it.key() == key; ++it) {
  1991         const QDBusConnectionPrivate::SignalHook &entry = it.value();
  2002         const QDBusConnectionPrivate::SignalHook &entry = it.value();
  1992         if (entry.service == hook.service &&
  2003         if (entry.service == hook.service &&
  1993             entry.owner == hook.owner &&
       
  1994             entry.path == hook.path &&
  2004             entry.path == hook.path &&
  1995             entry.signature == hook.signature &&
  2005             entry.signature == hook.signature &&
  1996             entry.obj == hook.obj &&
  2006             entry.obj == hook.obj &&
  1997             entry.midx == hook.midx) {
  2007             entry.midx == hook.midx) {
  1998             // no need to compare the parameters if it's the same slot
  2008             // no need to compare the parameters if it's the same slot
  2033             Q_ASSERT(false);
  2043             Q_ASSERT(false);
  2034         } else {
  2044         } else {
  2035             // Successfully connected the signal
  2045             // Successfully connected the signal
  2036             // Do we need to watch for this name?
  2046             // Do we need to watch for this name?
  2037             if (shouldWatchService(hook.service)) {
  2047             if (shouldWatchService(hook.service)) {
  2038                 WatchedServicesHash::Iterator it = watchedServiceNames.find(hook.service);
  2048                 WatchedServicesHash::mapped_type &data = watchedServices[hook.service];
  2039                 if (it != watchedServiceNames.end()) {
  2049                 if (data.refcount) {
  2040                     // already watching
  2050                     // already watching
  2041                     ++it.value();
  2051                     ++data.refcount;
  2042                 } else {
  2052                 } else {
  2043                     // we need to watch for this service changing
  2053                     // we need to watch for this service changing
  2044                     QString dbusServerService = QLatin1String(DBUS_SERVICE_DBUS);
  2054                     QString dbusServerService = QLatin1String(DBUS_SERVICE_DBUS);
  2045                     connectSignal(dbusServerService, dbusServerService, QString(), QLatin1String(DBUS_INTERFACE_DBUS),
  2055                     connectSignal(dbusServerService, QString(), QLatin1String(DBUS_INTERFACE_DBUS),
  2046                                   QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(),
  2056                                   QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(),
  2047                                   this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
  2057                                   this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
       
  2058                     data.owner = getNameOwnerNoCache(hook.service);
       
  2059                     qDBusDebug() << this << "Watching service" << hook.service << "for owner changes (current owner:"
       
  2060                             << data.owner << ")";
  2048                 }
  2061                 }
  2049             }
  2062             }
  2050         }
  2063         }
  2051     }
  2064     }
  2052 }
  2065 }
  2062     QString name2 = name;
  2075     QString name2 = name;
  2063     if (name2.isNull())
  2076     if (name2.isNull())
  2064         name2.detach();
  2077         name2.detach();
  2065 
  2078 
  2066     hook.signature = signature;
  2079     hook.signature = signature;
  2067     if (!prepareHook(hook, key, service, QString(), path, interface, name, argumentMatch, receiver, slot, 0, false))
  2080     if (!prepareHook(hook, key, service, path, interface, name, argumentMatch, receiver, slot, 0, false))
  2068         return false;           // don't disconnect
  2081         return false;           // don't disconnect
  2069 
  2082 
  2070     // avoid duplicating:
  2083     // avoid duplicating:
  2071     QDBusConnectionPrivate::SignalHookHash::Iterator it = signalHooks.find(key);
  2084     QDBusConnectionPrivate::SignalHookHash::Iterator it = signalHooks.find(key);
  2072     QDBusConnectionPrivate::SignalHookHash::Iterator end = signalHooks.end();
  2085     QDBusConnectionPrivate::SignalHookHash::Iterator end = signalHooks.end();
  2073     for ( ; it != end && it.key() == key; ++it) {
  2086     for ( ; it != end && it.key() == key; ++it) {
  2074         const QDBusConnectionPrivate::SignalHook &entry = it.value();
  2087         const QDBusConnectionPrivate::SignalHook &entry = it.value();
  2075         if (entry.service == hook.service &&
  2088         if (entry.service == hook.service &&
  2076             //entry.owner == hook.owner &&
       
  2077             entry.path == hook.path &&
  2089             entry.path == hook.path &&
  2078             entry.signature == hook.signature &&
  2090             entry.signature == hook.signature &&
  2079             entry.obj == hook.obj &&
  2091             entry.obj == hook.obj &&
  2080             entry.midx == hook.midx) {
  2092             entry.midx == hook.midx) {
  2081             // no need to compare the parameters if it's the same slot
  2093             // no need to compare the parameters if it's the same slot
  2091 QDBusConnectionPrivate::SignalHookHash::Iterator
  2103 QDBusConnectionPrivate::SignalHookHash::Iterator
  2092 QDBusConnectionPrivate::disconnectSignal(SignalHookHash::Iterator &it)
  2104 QDBusConnectionPrivate::disconnectSignal(SignalHookHash::Iterator &it)
  2093 {
  2105 {
  2094     const SignalHook &hook = it.value();
  2106     const SignalHook &hook = it.value();
  2095 
  2107 
  2096     WatchedServicesHash::Iterator sit = watchedServiceNames.find(hook.service);
  2108     WatchedServicesHash::Iterator sit = watchedServices.find(hook.service);
  2097     if (sit != watchedServiceNames.end()) {
  2109     if (sit != watchedServices.end()) {
  2098         if (sit.value() == 1) {
  2110         if (sit.value().refcount == 1) {
  2099             watchedServiceNames.erase(sit);
  2111             watchedServices.erase(sit);
  2100             QString dbusServerService = QLatin1String(DBUS_SERVICE_DBUS);
  2112             QString dbusServerService = QLatin1String(DBUS_SERVICE_DBUS);
  2101             disconnectSignal(dbusServerService, QString(), QLatin1String(DBUS_INTERFACE_DBUS),
  2113             disconnectSignal(dbusServerService, QString(), QLatin1String(DBUS_INTERFACE_DBUS),
  2102                           QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(),
  2114                           QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(),
  2103                           this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
  2115                           this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
  2104         } else {
  2116         } else {
  2105             --sit.value();
  2117             --sit.value().refcount;
  2106         }
  2118         }
  2107     }
  2119     }
  2108 
  2120 
  2109     bool erase = false;
  2121     bool erase = false;
  2110     MatchRefCountHash::iterator i = matchRefCounts.find(hook.matchRule);
  2122     MatchRefCountHash::iterator i = matchRefCounts.find(hook.matchRule);
  2152                 this, SLOT(relaySignal(QObject*,const QMetaObject*,int,QVariantList)),
  2164                 this, SLOT(relaySignal(QObject*,const QMetaObject*,int,QVariantList)),
  2153                 Qt::DirectConnection);
  2165                 Qt::DirectConnection);
  2154     }
  2166     }
  2155 }
  2167 }
  2156 
  2168 
  2157 void QDBusConnectionPrivate::connectRelay(const QString &service, const QString &owner,
  2169 void QDBusConnectionPrivate::connectRelay(const QString &service,
  2158                                           const QString &path, const QString &interface,
  2170                                           const QString &path, const QString &interface,
  2159                                           QDBusAbstractInterface *receiver,
  2171                                           QDBusAbstractInterface *receiver,
  2160                                           const char *signal)
  2172                                           const char *signal)
  2161 {
  2173 {
  2162     // this function is called by QDBusAbstractInterface when one of its signals is connected
  2174     // this function is called by QDBusAbstractInterface when one of its signals is connected
  2163     // we set up a relay from D-Bus into it
  2175     // we set up a relay from D-Bus into it
  2164     SignalHook hook;
  2176     SignalHook hook;
  2165     QString key;
  2177     QString key;
  2166 
  2178 
  2167     if (!prepareHook(hook, key, service, owner, path, interface, QString(), QStringList(), receiver, signal,
  2179     if (!prepareHook(hook, key, service, path, interface, QString(), QStringList(), receiver, signal,
  2168                      QDBusAbstractInterface::staticMetaObject.methodCount(), true))
  2180                      QDBusAbstractInterface::staticMetaObject.methodCount(), true))
  2169         return;                 // don't connect
  2181         return;                 // don't connect
  2170 
  2182 
  2171     // add it to our list:
  2183     // add it to our list:
  2172     QDBusWriteLocker locker(ConnectRelayAction, this);
  2184     QDBusWriteLocker locker(ConnectRelayAction, this);
  2173     SignalHookHash::ConstIterator it = signalHooks.find(key);
  2185     SignalHookHash::ConstIterator it = signalHooks.find(key);
  2174     SignalHookHash::ConstIterator end = signalHooks.constEnd();
  2186     SignalHookHash::ConstIterator end = signalHooks.constEnd();
  2175     for ( ; it != end && it.key() == key; ++it) {
  2187     for ( ; it != end && it.key() == key; ++it) {
  2176         const SignalHook &entry = it.value();
  2188         const SignalHook &entry = it.value();
  2177         if (entry.service == hook.service &&
  2189         if (entry.service == hook.service &&
  2178             entry.owner == hook.owner &&
       
  2179             entry.path == hook.path &&
  2190             entry.path == hook.path &&
  2180             entry.signature == hook.signature &&
  2191             entry.signature == hook.signature &&
  2181             entry.obj == hook.obj &&
  2192             entry.obj == hook.obj &&
  2182             entry.midx == hook.midx)
  2193             entry.midx == hook.midx)
  2183             return;             // already there, no need to re-add
  2194             return;             // already there, no need to re-add
  2184     }
  2195     }
  2185 
  2196 
  2186     connectSignal(key, hook);
  2197     connectSignal(key, hook);
  2187 }
  2198 }
  2188 
  2199 
  2189 void QDBusConnectionPrivate::disconnectRelay(const QString &service, const QString &owner,
  2200 void QDBusConnectionPrivate::disconnectRelay(const QString &service,
  2190                                              const QString &path, const QString &interface,
  2201                                              const QString &path, const QString &interface,
  2191                                              QDBusAbstractInterface *receiver,
  2202                                              QDBusAbstractInterface *receiver,
  2192                                              const char *signal)
  2203                                              const char *signal)
  2193 {
  2204 {
  2194     // this function is called by QDBusAbstractInterface when one of its signals is disconnected
  2205     // this function is called by QDBusAbstractInterface when one of its signals is disconnected
  2195     // we remove relay from D-Bus into it
  2206     // we remove relay from D-Bus into it
  2196     SignalHook hook;
  2207     SignalHook hook;
  2197     QString key;
  2208     QString key;
  2198 
  2209 
  2199     if (!prepareHook(hook, key, service, owner, path, interface, QString(), QStringList(), receiver, signal,
  2210     if (!prepareHook(hook, key, service, path, interface, QString(), QStringList(), receiver, signal,
  2200                      QDBusAbstractInterface::staticMetaObject.methodCount(), true))
  2211                      QDBusAbstractInterface::staticMetaObject.methodCount(), true))
  2201         return;                 // don't connect
  2212         return;                 // don't connect
  2202 
  2213 
  2203     // remove it from our list:
  2214     // remove it from our list:
  2204     QDBusWriteLocker locker(DisconnectRelayAction, this);
  2215     QDBusWriteLocker locker(DisconnectRelayAction, this);
  2205     SignalHookHash::Iterator it = signalHooks.find(key);
  2216     SignalHookHash::Iterator it = signalHooks.find(key);
  2206     SignalHookHash::Iterator end = signalHooks.end();
  2217     SignalHookHash::Iterator end = signalHooks.end();
  2207     for ( ; it != end && it.key() == key; ++it) {
  2218     for ( ; it != end && it.key() == key; ++it) {
  2208         const SignalHook &entry = it.value();
  2219         const SignalHook &entry = it.value();
  2209         if (entry.service == hook.service &&
  2220         if (entry.service == hook.service &&
  2210             entry.owner == hook.owner &&
       
  2211             entry.path == hook.path &&
  2221             entry.path == hook.path &&
  2212             entry.signature == hook.signature &&
  2222             entry.signature == hook.signature &&
  2213             entry.obj == hook.obj &&
  2223             entry.obj == hook.obj &&
  2214             entry.midx == hook.midx) {
  2224             entry.midx == hook.midx) {
  2215             // found it
  2225             // found it
  2223 
  2233 
  2224 QString QDBusConnectionPrivate::getNameOwner(const QString& serviceName)
  2234 QString QDBusConnectionPrivate::getNameOwner(const QString& serviceName)
  2225 {
  2235 {
  2226     if (QDBusUtil::isValidUniqueConnectionName(serviceName))
  2236     if (QDBusUtil::isValidUniqueConnectionName(serviceName))
  2227         return serviceName;
  2237         return serviceName;
  2228     if (!connection || !QDBusUtil::isValidBusName(serviceName))
  2238     if (!connection)
  2229         return QString();
  2239         return QString();
  2230 
  2240 
       
  2241     {
       
  2242         // acquire a read lock for the cache
       
  2243         QReadLocker locker(&lock);
       
  2244         WatchedServicesHash::ConstIterator it = watchedServices.constFind(serviceName);
       
  2245         if (it != watchedServices.constEnd())
       
  2246             return it->owner;
       
  2247     }
       
  2248 
       
  2249     // not cached
       
  2250     return getNameOwnerNoCache(serviceName);
       
  2251 }
       
  2252 
       
  2253 QString QDBusConnectionPrivate::getNameOwnerNoCache(const QString &serviceName)
       
  2254 {
  2231     QDBusMessage msg = QDBusMessage::createMethodCall(QLatin1String(DBUS_SERVICE_DBUS),
  2255     QDBusMessage msg = QDBusMessage::createMethodCall(QLatin1String(DBUS_SERVICE_DBUS),
  2232             QLatin1String(DBUS_PATH_DBUS), QLatin1String(DBUS_INTERFACE_DBUS),
  2256             QLatin1String(DBUS_PATH_DBUS), QLatin1String(DBUS_INTERFACE_DBUS),
  2233             QLatin1String("GetNameOwner"));
  2257             QLatin1String("GetNameOwner"));
  2234     QDBusMessagePrivate::setParametersValidated(msg, true);
  2258     QDBusMessagePrivate::setParametersValidated(msg, true);
  2235     msg << serviceName;
  2259     msg << serviceName;