src/dbus/qdbusintegrator.cpp
changeset 7 f7bc934e204c
parent 3 41300fa6a67c
child 29 b72c6db6890b
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
     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     connectSignal(busService, QString(), QString(), QLatin1String("NameAcquired"), QStringList(), QString(),
  1656                   this, SLOT(registerService(QString)));
  1664                   this, SLOT(registerService(QString)));
  1657     connectSignal(busService, QString(), QString(), QString(), QLatin1String("NameLost"), QStringList(), QString(),
  1665     connectSignal(busService, QString(), QString(), QLatin1String("NameLost"), QStringList(), QString(),
  1658                   this, SLOT(unregisterService(QString)));
  1666                   this, SLOT(unregisterService(QString)));
  1659 
  1667 
  1660 
  1668 
  1661     q_dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0);
  1669     q_dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0);
  1662 
  1670 
  1663     //qDebug("base service: %s", service);
  1671     qDBusDebug() << this << ": connected successfully";
  1664 
  1672 
  1665     // schedule a dispatch:
  1673     // schedule a dispatch:
  1666     QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
  1674     QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
  1667 }
  1675 }
  1668 
  1676 
  1693         // decode the message
  1701         // decode the message
  1694         DBusMessage *reply = q_dbus_pending_call_steal_reply(call->pending);
  1702         DBusMessage *reply = q_dbus_pending_call_steal_reply(call->pending);
  1695         msg = QDBusMessagePrivate::fromDBusMessage(reply);
  1703         msg = QDBusMessagePrivate::fromDBusMessage(reply);
  1696         q_dbus_message_unref(reply);
  1704         q_dbus_message_unref(reply);
  1697     }
  1705     }
  1698     qDBusDebug() << QThread::currentThread() << "got message reply (async):" << msg;
  1706     qDBusDebug() << connection << "got message reply (async):" << msg;
  1699 
  1707 
  1700     // Check if the reply has the expected signature
  1708     // Check if the reply has the expected signature
  1701     call->checkReceivedSignature();
  1709     call->checkReceivedSignature();
  1702 
  1710 
  1703     if (!call->receiver.isNull() && call->methodIdx != -1 && msg.type() == QDBusMessage::ReplyMessage) {
  1711     if (!call->receiver.isNull() && call->methodIdx != -1 && msg.type() == QDBusMessage::ReplyMessage) {
  1761         return 0;
  1769         return 0;
  1762     }
  1770     }
  1763 
  1771 
  1764     q_dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything
  1772     q_dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything
  1765 
  1773 
  1766     qDBusDebug() << QThread::currentThread() << "sending message (no reply):" << message;
  1774     qDBusDebug() << this << "sending message (no reply):" << message;
  1767     checkThread();
  1775     checkThread();
  1768     bool isOk = q_dbus_connection_send(connection, msg, 0);
  1776     bool isOk = q_dbus_connection_send(connection, msg, 0);
  1769     int serial = 0;
  1777     int serial = 0;
  1770     if (isOk)
  1778     if (isOk)
  1771         serial = q_dbus_message_get_serial(msg);
  1779         serial = q_dbus_message_get_serial(msg);
  1793                      qPrintable(err.message()));
  1801                      qPrintable(err.message()));
  1794             lastError = err;
  1802             lastError = err;
  1795             return QDBusMessage::createError(err);
  1803             return QDBusMessage::createError(err);
  1796         }
  1804         }
  1797 
  1805 
  1798         qDBusDebug() << QThread::currentThread() << "sending message (blocking):" << message;
  1806         qDBusDebug() << this << "sending message (blocking):" << message;
  1799         QDBusErrorInternal error;
  1807         QDBusErrorInternal error;
  1800         DBusMessage *reply = q_dbus_connection_send_with_reply_and_block(connection, msg, timeout, error);
  1808         DBusMessage *reply = q_dbus_connection_send_with_reply_and_block(connection, msg, timeout, error);
  1801 
  1809 
  1802         q_dbus_message_unref(msg);
  1810         q_dbus_message_unref(msg);
  1803 
  1811 
  1806             return QDBusMessage::createError(err);
  1814             return QDBusMessage::createError(err);
  1807         }
  1815         }
  1808 
  1816 
  1809         QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(reply);
  1817         QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(reply);
  1810         q_dbus_message_unref(reply);
  1818         q_dbus_message_unref(reply);
  1811         qDBusDebug() << QThread::currentThread() << "got message reply (blocking):" << amsg;
  1819         qDBusDebug() << this << "got message reply (blocking):" << amsg;
  1812 
  1820 
  1813         return amsg;
  1821         return amsg;
  1814     } else { // use the event loop
  1822     } else { // use the event loop
  1815         QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, timeout);
  1823         QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, timeout);
  1816         Q_ASSERT(pcall);
  1824         Q_ASSERT(pcall);
  1817 
  1825 
  1818         if (pcall->replyMessage.type() != QDBusMessage::InvalidMessage) {
  1826         if (pcall->replyMessage.type() == QDBusMessage::InvalidMessage) {
  1819             pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
  1827             pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
  1820             QEventLoop loop;
  1828             QEventLoop loop;
  1821             loop.connect(pcall->watcherHelper, SIGNAL(reply(QDBusMessage)), SLOT(quit()));
  1829             loop.connect(pcall->watcherHelper, SIGNAL(reply(QDBusMessage)), SLOT(quit()));
  1822             loop.connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), SLOT(quit()));
  1830             loop.connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), SLOT(quit()));
  1823 
  1831 
  1833     }
  1841     }
  1834 }
  1842 }
  1835 
  1843 
  1836 QDBusMessage QDBusConnectionPrivate::sendWithReplyLocal(const QDBusMessage &message)
  1844 QDBusMessage QDBusConnectionPrivate::sendWithReplyLocal(const QDBusMessage &message)
  1837 {
  1845 {
  1838     qDBusDebug() << QThread::currentThread() << "sending message via local-loop:" << message;
  1846     qDBusDebug() << this << "sending message via local-loop:" << message;
  1839 
  1847 
  1840     QDBusMessage localCallMsg = QDBusMessagePrivate::makeLocal(*this, message);
  1848     QDBusMessage localCallMsg = QDBusMessagePrivate::makeLocal(*this, message);
  1841     bool handled = handleMessage(localCallMsg);
  1849     bool handled = handleMessage(localCallMsg);
  1842 
  1850 
  1843     if (!handled) {
  1851     if (!handled) {
  1860             QDBusError(QDBusError::InternalError,
  1868             QDBusError(QDBusError::InternalError,
  1861                        QLatin1String("local-loop message cannot have delayed replies")));
  1869                        QLatin1String("local-loop message cannot have delayed replies")));
  1862     }
  1870     }
  1863 
  1871 
  1864     // there is a reply
  1872     // there is a reply
  1865     qDBusDebug() << QThread::currentThread() << "got message via local-loop:" << localReplyMsg;
  1873     qDBusDebug() << this << "got message via local-loop:" << localReplyMsg;
  1866     return localReplyMsg;
  1874     return localReplyMsg;
  1867 }
  1875 }
  1868 
  1876 
  1869 QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message,
  1877 QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message,
  1870                                                                     int timeout)
  1878                                                                     int timeout)
  1894         pcall->replyMessage = QDBusMessage::createError(error);
  1902         pcall->replyMessage = QDBusMessage::createError(error);
  1895         lastError = error;
  1903         lastError = error;
  1896         return pcall;
  1904         return pcall;
  1897     }
  1905     }
  1898 
  1906 
  1899     qDBusDebug() << QThread::currentThread() << "sending message (async):" << message;
  1907     qDBusDebug() << this << "sending message (async):" << message;
  1900     DBusPendingCall *pending = 0;
  1908     DBusPendingCall *pending = 0;
  1901 
  1909 
  1902     QDBusDispatchLocker locker(SendWithReplyAsyncAction, this);
  1910     QDBusDispatchLocker locker(SendWithReplyAsyncAction, this);
  1903     if (q_dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
  1911     if (q_dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
  1904         if (pending) {
  1912         if (pending) {
  1927                                                int timeout)
  1935                                                int timeout)
  1928 {
  1936 {
  1929     QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, timeout);
  1937     QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, timeout);
  1930     Q_ASSERT(pcall);
  1938     Q_ASSERT(pcall);
  1931 
  1939 
  1932     // has it already finished (dispatched locally)?
  1940     // has it already finished with success (dispatched locally)?
  1933     if (pcall->replyMessage.type() == QDBusMessage::ReplyMessage) {
  1941     if (pcall->replyMessage.type() == QDBusMessage::ReplyMessage) {
  1934         pcall->setReplyCallback(receiver, returnMethod);
  1942         pcall->setReplyCallback(receiver, returnMethod);
  1935         processFinishedCall(pcall);
  1943         processFinishedCall(pcall);
  1936         delete pcall;
  1944         delete pcall;
  1937         return 1;
  1945         return 1;
  1938     }
  1946     }
  1939 
  1947 
       
  1948     // either it hasn't finished or it has finished with error
       
  1949     if (errorMethod) {
       
  1950         pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
       
  1951         connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), receiver, errorMethod,
       
  1952                 Qt::QueuedConnection);
       
  1953         pcall->watcherHelper->moveToThread(thread());
       
  1954     }
       
  1955 
  1940     // has it already finished and is an error reply message?
  1956     // has it already finished and is an error reply message?
  1941     if (pcall->replyMessage.type() == QDBusMessage::ErrorMessage) {
  1957     if (pcall->replyMessage.type() == QDBusMessage::ErrorMessage) {
  1942         if (errorMethod) {
       
  1943             pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
       
  1944             connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), receiver, errorMethod);
       
  1945             pcall->watcherHelper->moveToThread(thread());
       
  1946         }
       
  1947         processFinishedCall(pcall);
  1958         processFinishedCall(pcall);
  1948         delete pcall;
  1959         delete pcall;
  1949         return 1;
  1960         return 1;
  1950     }
  1961     }
  1951 
  1962 
  1952     // has it already finished with error?
       
  1953     if (pcall->replyMessage.type() != QDBusMessage::InvalidMessage) {
       
  1954         delete pcall;
       
  1955         return 0;
       
  1956     }
       
  1957 
       
  1958     pcall->autoDelete = true;
  1963     pcall->autoDelete = true;
  1959     pcall->ref.ref();
  1964     pcall->ref.ref();
  1960 
       
  1961     pcall->setReplyCallback(receiver, returnMethod);
  1965     pcall->setReplyCallback(receiver, returnMethod);
  1962     if (errorMethod) {
       
  1963         pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
       
  1964         connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), receiver, errorMethod);
       
  1965         pcall->watcherHelper->moveToThread(thread());
       
  1966     }
       
  1967 
  1966 
  1968     return 1;
  1967     return 1;
  1969 }
  1968 }
  1970 
  1969 
  1971 bool QDBusConnectionPrivate::connectSignal(const QString &service, const QString &owner,
  1970 bool QDBusConnectionPrivate::connectSignal(const QString &service,
  1972                                            const QString &path, const QString &interface, const QString &name,
  1971                                            const QString &path, const QString &interface, const QString &name,
  1973                                            const QStringList &argumentMatch, const QString &signature,
  1972                                            const QStringList &argumentMatch, const QString &signature,
  1974                                            QObject *receiver, const char *slot)
  1973                                            QObject *receiver, const char *slot)
  1975 {
  1974 {
  1976     // check the slot
  1975     // check the slot
  1979     QString name2 = name;
  1978     QString name2 = name;
  1980     if (name2.isNull())
  1979     if (name2.isNull())
  1981         name2.detach();
  1980         name2.detach();
  1982 
  1981 
  1983     hook.signature = signature;
  1982     hook.signature = signature;
  1984     if (!prepareHook(hook, key, service, owner, path, interface, name, argumentMatch, receiver, slot, 0, false))
  1983     if (!prepareHook(hook, key, service, path, interface, name, argumentMatch, receiver, slot, 0, false))
  1985         return false;           // don't connect
  1984         return false;           // don't connect
  1986 
  1985 
  1987     // avoid duplicating:
  1986     // avoid duplicating:
  1988     QDBusConnectionPrivate::SignalHookHash::ConstIterator it = signalHooks.find(key);
  1987     QDBusConnectionPrivate::SignalHookHash::ConstIterator it = signalHooks.find(key);
  1989     QDBusConnectionPrivate::SignalHookHash::ConstIterator end = signalHooks.constEnd();
  1988     QDBusConnectionPrivate::SignalHookHash::ConstIterator end = signalHooks.constEnd();
  1990     for ( ; it != end && it.key() == key; ++it) {
  1989     for ( ; it != end && it.key() == key; ++it) {
  1991         const QDBusConnectionPrivate::SignalHook &entry = it.value();
  1990         const QDBusConnectionPrivate::SignalHook &entry = it.value();
  1992         if (entry.service == hook.service &&
  1991         if (entry.service == hook.service &&
  1993             entry.owner == hook.owner &&
       
  1994             entry.path == hook.path &&
  1992             entry.path == hook.path &&
  1995             entry.signature == hook.signature &&
  1993             entry.signature == hook.signature &&
  1996             entry.obj == hook.obj &&
  1994             entry.obj == hook.obj &&
  1997             entry.midx == hook.midx) {
  1995             entry.midx == hook.midx &&
       
  1996             entry.argumentMatch == hook.argumentMatch) {
  1998             // no need to compare the parameters if it's the same slot
  1997             // no need to compare the parameters if it's the same slot
  1999             return true;        // already there
  1998             return true;        // already there
  2000         }
  1999         }
  2001     }
  2000     }
  2002 
  2001 
  2033             Q_ASSERT(false);
  2032             Q_ASSERT(false);
  2034         } else {
  2033         } else {
  2035             // Successfully connected the signal
  2034             // Successfully connected the signal
  2036             // Do we need to watch for this name?
  2035             // Do we need to watch for this name?
  2037             if (shouldWatchService(hook.service)) {
  2036             if (shouldWatchService(hook.service)) {
  2038                 WatchedServicesHash::Iterator it = watchedServiceNames.find(hook.service);
  2037                 WatchedServicesHash::mapped_type &data = watchedServices[hook.service];
  2039                 if (it != watchedServiceNames.end()) {
  2038                 if (++data.refcount == 1) {
  2040                     // already watching
       
  2041                     ++it.value();
       
  2042                 } else {
       
  2043                     // we need to watch for this service changing
  2039                     // we need to watch for this service changing
  2044                     QString dbusServerService = QLatin1String(DBUS_SERVICE_DBUS);
  2040                     QString dbusServerService = QLatin1String(DBUS_SERVICE_DBUS);
  2045                     connectSignal(dbusServerService, dbusServerService, QString(), QLatin1String(DBUS_INTERFACE_DBUS),
  2041                     connectSignal(dbusServerService, QString(), QLatin1String(DBUS_INTERFACE_DBUS),
  2046                                   QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(),
  2042                                   QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(),
  2047                                   this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
  2043                                   this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
       
  2044                     data.owner = getNameOwnerNoCache(hook.service);
       
  2045                     qDBusDebug() << this << "Watching service" << hook.service << "for owner changes (current owner:"
       
  2046                             << data.owner << ")";
  2048                 }
  2047                 }
  2049             }
  2048             }
  2050         }
  2049         }
  2051     }
  2050     }
  2052 }
  2051 }
  2062     QString name2 = name;
  2061     QString name2 = name;
  2063     if (name2.isNull())
  2062     if (name2.isNull())
  2064         name2.detach();
  2063         name2.detach();
  2065 
  2064 
  2066     hook.signature = signature;
  2065     hook.signature = signature;
  2067     if (!prepareHook(hook, key, service, QString(), path, interface, name, argumentMatch, receiver, slot, 0, false))
  2066     if (!prepareHook(hook, key, service, path, interface, name, argumentMatch, receiver, slot, 0, false))
  2068         return false;           // don't disconnect
  2067         return false;           // don't disconnect
  2069 
  2068 
  2070     // avoid duplicating:
  2069     // avoid duplicating:
  2071     QDBusConnectionPrivate::SignalHookHash::Iterator it = signalHooks.find(key);
  2070     QDBusConnectionPrivate::SignalHookHash::Iterator it = signalHooks.find(key);
  2072     QDBusConnectionPrivate::SignalHookHash::Iterator end = signalHooks.end();
  2071     QDBusConnectionPrivate::SignalHookHash::Iterator end = signalHooks.end();
  2073     for ( ; it != end && it.key() == key; ++it) {
  2072     for ( ; it != end && it.key() == key; ++it) {
  2074         const QDBusConnectionPrivate::SignalHook &entry = it.value();
  2073         const QDBusConnectionPrivate::SignalHook &entry = it.value();
  2075         if (entry.service == hook.service &&
  2074         if (entry.service == hook.service &&
  2076             //entry.owner == hook.owner &&
       
  2077             entry.path == hook.path &&
  2075             entry.path == hook.path &&
  2078             entry.signature == hook.signature &&
  2076             entry.signature == hook.signature &&
  2079             entry.obj == hook.obj &&
  2077             entry.obj == hook.obj &&
  2080             entry.midx == hook.midx) {
  2078             entry.midx == hook.midx &&
       
  2079             entry.argumentMatch == hook.argumentMatch) {
  2081             // no need to compare the parameters if it's the same slot
  2080             // no need to compare the parameters if it's the same slot
  2082             disconnectSignal(it);
  2081             disconnectSignal(it);
  2083             return true;        // it was there
  2082             return true;        // it was there
  2084         }
  2083         }
  2085     }
  2084     }
  2090 
  2089 
  2091 QDBusConnectionPrivate::SignalHookHash::Iterator
  2090 QDBusConnectionPrivate::SignalHookHash::Iterator
  2092 QDBusConnectionPrivate::disconnectSignal(SignalHookHash::Iterator &it)
  2091 QDBusConnectionPrivate::disconnectSignal(SignalHookHash::Iterator &it)
  2093 {
  2092 {
  2094     const SignalHook &hook = it.value();
  2093     const SignalHook &hook = it.value();
  2095 
       
  2096     WatchedServicesHash::Iterator sit = watchedServiceNames.find(hook.service);
       
  2097     if (sit != watchedServiceNames.end()) {
       
  2098         if (sit.value() == 1) {
       
  2099             watchedServiceNames.erase(sit);
       
  2100             QString dbusServerService = QLatin1String(DBUS_SERVICE_DBUS);
       
  2101             disconnectSignal(dbusServerService, QString(), QLatin1String(DBUS_INTERFACE_DBUS),
       
  2102                           QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(),
       
  2103                           this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
       
  2104         } else {
       
  2105             --sit.value();
       
  2106         }
       
  2107     }
       
  2108 
  2094 
  2109     bool erase = false;
  2095     bool erase = false;
  2110     MatchRefCountHash::iterator i = matchRefCounts.find(hook.matchRule);
  2096     MatchRefCountHash::iterator i = matchRefCounts.find(hook.matchRule);
  2111     if (i == matchRefCounts.end()) {
  2097     if (i == matchRefCounts.end()) {
  2112         qWarning("QDBusConnectionPrivate::disconnectSignal: MatchRule not found in matchRefCounts!!");
  2098         qWarning("QDBusConnectionPrivate::disconnectSignal: MatchRule not found in matchRefCounts!!");
  2122 
  2108 
  2123     // we don't care about errors here
  2109     // we don't care about errors here
  2124     if (connection && erase) {
  2110     if (connection && erase) {
  2125         qDBusDebug("Removing rule: %s", hook.matchRule.constData());
  2111         qDBusDebug("Removing rule: %s", hook.matchRule.constData());
  2126         q_dbus_bus_remove_match(connection, hook.matchRule, NULL);
  2112         q_dbus_bus_remove_match(connection, hook.matchRule, NULL);
       
  2113 
       
  2114         // Successfully disconnected the signal
       
  2115         // Were we watching for this name?
       
  2116         WatchedServicesHash::Iterator sit = watchedServices.find(hook.service);
       
  2117         if (sit != watchedServices.end()) {
       
  2118             if (--sit.value().refcount == 0) {
       
  2119                 watchedServices.erase(sit);
       
  2120                 QString dbusServerService = QLatin1String(DBUS_SERVICE_DBUS);
       
  2121                 disconnectSignal(dbusServerService, QString(), QLatin1String(DBUS_INTERFACE_DBUS),
       
  2122                               QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(),
       
  2123                               this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
       
  2124             }
       
  2125         }
       
  2126 
  2127     }
  2127     }
  2128 
  2128 
  2129     return signalHooks.erase(it);
  2129     return signalHooks.erase(it);
  2130 }
  2130 }
  2131 
  2131 
  2152                 this, SLOT(relaySignal(QObject*,const QMetaObject*,int,QVariantList)),
  2152                 this, SLOT(relaySignal(QObject*,const QMetaObject*,int,QVariantList)),
  2153                 Qt::DirectConnection);
  2153                 Qt::DirectConnection);
  2154     }
  2154     }
  2155 }
  2155 }
  2156 
  2156 
  2157 void QDBusConnectionPrivate::connectRelay(const QString &service, const QString &owner,
  2157 void QDBusConnectionPrivate::connectRelay(const QString &service,
  2158                                           const QString &path, const QString &interface,
  2158                                           const QString &path, const QString &interface,
  2159                                           QDBusAbstractInterface *receiver,
  2159                                           QDBusAbstractInterface *receiver,
  2160                                           const char *signal)
  2160                                           const char *signal)
  2161 {
  2161 {
  2162     // this function is called by QDBusAbstractInterface when one of its signals is connected
  2162     // this function is called by QDBusAbstractInterface when one of its signals is connected
  2163     // we set up a relay from D-Bus into it
  2163     // we set up a relay from D-Bus into it
  2164     SignalHook hook;
  2164     SignalHook hook;
  2165     QString key;
  2165     QString key;
  2166 
  2166 
  2167     if (!prepareHook(hook, key, service, owner, path, interface, QString(), QStringList(), receiver, signal,
  2167     if (!prepareHook(hook, key, service, path, interface, QString(), QStringList(), receiver, signal,
  2168                      QDBusAbstractInterface::staticMetaObject.methodCount(), true))
  2168                      QDBusAbstractInterface::staticMetaObject.methodCount(), true))
  2169         return;                 // don't connect
  2169         return;                 // don't connect
  2170 
  2170 
  2171     // add it to our list:
  2171     // add it to our list:
  2172     QDBusWriteLocker locker(ConnectRelayAction, this);
  2172     QDBusWriteLocker locker(ConnectRelayAction, this);
  2173     SignalHookHash::ConstIterator it = signalHooks.find(key);
  2173     SignalHookHash::ConstIterator it = signalHooks.find(key);
  2174     SignalHookHash::ConstIterator end = signalHooks.constEnd();
  2174     SignalHookHash::ConstIterator end = signalHooks.constEnd();
  2175     for ( ; it != end && it.key() == key; ++it) {
  2175     for ( ; it != end && it.key() == key; ++it) {
  2176         const SignalHook &entry = it.value();
  2176         const SignalHook &entry = it.value();
  2177         if (entry.service == hook.service &&
  2177         if (entry.service == hook.service &&
  2178             entry.owner == hook.owner &&
       
  2179             entry.path == hook.path &&
  2178             entry.path == hook.path &&
  2180             entry.signature == hook.signature &&
  2179             entry.signature == hook.signature &&
  2181             entry.obj == hook.obj &&
  2180             entry.obj == hook.obj &&
  2182             entry.midx == hook.midx)
  2181             entry.midx == hook.midx)
  2183             return;             // already there, no need to re-add
  2182             return;             // already there, no need to re-add
  2184     }
  2183     }
  2185 
  2184 
  2186     connectSignal(key, hook);
  2185     connectSignal(key, hook);
  2187 }
  2186 }
  2188 
  2187 
  2189 void QDBusConnectionPrivate::disconnectRelay(const QString &service, const QString &owner,
  2188 void QDBusConnectionPrivate::disconnectRelay(const QString &service,
  2190                                              const QString &path, const QString &interface,
  2189                                              const QString &path, const QString &interface,
  2191                                              QDBusAbstractInterface *receiver,
  2190                                              QDBusAbstractInterface *receiver,
  2192                                              const char *signal)
  2191                                              const char *signal)
  2193 {
  2192 {
  2194     // this function is called by QDBusAbstractInterface when one of its signals is disconnected
  2193     // this function is called by QDBusAbstractInterface when one of its signals is disconnected
  2195     // we remove relay from D-Bus into it
  2194     // we remove relay from D-Bus into it
  2196     SignalHook hook;
  2195     SignalHook hook;
  2197     QString key;
  2196     QString key;
  2198 
  2197 
  2199     if (!prepareHook(hook, key, service, owner, path, interface, QString(), QStringList(), receiver, signal,
  2198     if (!prepareHook(hook, key, service, path, interface, QString(), QStringList(), receiver, signal,
  2200                      QDBusAbstractInterface::staticMetaObject.methodCount(), true))
  2199                      QDBusAbstractInterface::staticMetaObject.methodCount(), true))
  2201         return;                 // don't connect
  2200         return;                 // don't connect
  2202 
  2201 
  2203     // remove it from our list:
  2202     // remove it from our list:
  2204     QDBusWriteLocker locker(DisconnectRelayAction, this);
  2203     QDBusWriteLocker locker(DisconnectRelayAction, this);
  2205     SignalHookHash::Iterator it = signalHooks.find(key);
  2204     SignalHookHash::Iterator it = signalHooks.find(key);
  2206     SignalHookHash::Iterator end = signalHooks.end();
  2205     SignalHookHash::Iterator end = signalHooks.end();
  2207     for ( ; it != end && it.key() == key; ++it) {
  2206     for ( ; it != end && it.key() == key; ++it) {
  2208         const SignalHook &entry = it.value();
  2207         const SignalHook &entry = it.value();
  2209         if (entry.service == hook.service &&
  2208         if (entry.service == hook.service &&
  2210             entry.owner == hook.owner &&
       
  2211             entry.path == hook.path &&
  2209             entry.path == hook.path &&
  2212             entry.signature == hook.signature &&
  2210             entry.signature == hook.signature &&
  2213             entry.obj == hook.obj &&
  2211             entry.obj == hook.obj &&
  2214             entry.midx == hook.midx) {
  2212             entry.midx == hook.midx) {
  2215             // found it
  2213             // found it
  2223 
  2221 
  2224 QString QDBusConnectionPrivate::getNameOwner(const QString& serviceName)
  2222 QString QDBusConnectionPrivate::getNameOwner(const QString& serviceName)
  2225 {
  2223 {
  2226     if (QDBusUtil::isValidUniqueConnectionName(serviceName))
  2224     if (QDBusUtil::isValidUniqueConnectionName(serviceName))
  2227         return serviceName;
  2225         return serviceName;
  2228     if (!connection || !QDBusUtil::isValidBusName(serviceName))
  2226     if (!connection)
  2229         return QString();
  2227         return QString();
  2230 
  2228 
       
  2229     {
       
  2230         // acquire a read lock for the cache
       
  2231         QReadLocker locker(&lock);
       
  2232         WatchedServicesHash::ConstIterator it = watchedServices.constFind(serviceName);
       
  2233         if (it != watchedServices.constEnd())
       
  2234             return it->owner;
       
  2235     }
       
  2236 
       
  2237     // not cached
       
  2238     return getNameOwnerNoCache(serviceName);
       
  2239 }
       
  2240 
       
  2241 QString QDBusConnectionPrivate::getNameOwnerNoCache(const QString &serviceName)
       
  2242 {
  2231     QDBusMessage msg = QDBusMessage::createMethodCall(QLatin1String(DBUS_SERVICE_DBUS),
  2243     QDBusMessage msg = QDBusMessage::createMethodCall(QLatin1String(DBUS_SERVICE_DBUS),
  2232             QLatin1String(DBUS_PATH_DBUS), QLatin1String(DBUS_INTERFACE_DBUS),
  2244             QLatin1String(DBUS_PATH_DBUS), QLatin1String(DBUS_INTERFACE_DBUS),
  2233             QLatin1String("GetNameOwner"));
  2245             QLatin1String("GetNameOwner"));
  2234     QDBusMessagePrivate::setParametersValidated(msg, true);
  2246     QDBusMessagePrivate::setParametersValidated(msg, true);
  2235     msg << serviceName;
  2247     msg << serviceName;