diff options
author | Weng Xuetian <wengxt@gmail.com> | 2016-03-03 21:56:53 -0800 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2016-04-28 05:38:10 +0000 |
commit | 9be4ee52021bbb3227611979319ab5e3106063b2 (patch) | |
tree | 63914720d6abe52ebd27a290713fee6a3d9e3c4f /src/dbus | |
parent | 8a7311532ba331252d87cbcc08ea676f106242e9 (diff) |
QtDBus: finish all pending call with error if disconnected
libdbus will send a local signal if connection gets disconnected. When
this happens, end all pending calls with QDBusError::Disconnected.
Task-number: QTBUG-51649
Change-Id: I5c7d2a468bb5da746d0c0e53e458c1e376f186a9
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/dbus')
-rw-r--r-- | src/dbus/dbus_minimal_p.h | 2 | ||||
-rw-r--r-- | src/dbus/qdbusconnection_p.h | 3 | ||||
-rw-r--r-- | src/dbus/qdbusintegrator.cpp | 41 | ||||
-rw-r--r-- | src/dbus/qdbusutil_p.h | 2 |
4 files changed, 42 insertions, 6 deletions
diff --git a/src/dbus/dbus_minimal_p.h b/src/dbus/dbus_minimal_p.h index f0a29540c8..8f25b24c61 100644 --- a/src/dbus/dbus_minimal_p.h +++ b/src/dbus/dbus_minimal_p.h @@ -99,9 +99,11 @@ typedef dbus_uint32_t dbus_bool_t; /* dbus-shared.h */ #define DBUS_SERVICE_DBUS "org.freedesktop.DBus" #define DBUS_PATH_DBUS "/org/freedesktop/DBus" +#define DBUS_PATH_LOCAL "/org/freedesktop/DBus/Local" #define DBUS_INTERFACE_DBUS "org.freedesktop.DBus" #define DBUS_INTERFACE_INTROSPECTABLE "org.freedesktop.DBus.Introspectable" #define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties" +#define DBUS_INTERFACE_LOCAL "org.freedesktop.DBus.Local" #define DBUS_NAME_FLAG_ALLOW_REPLACEMENT 0x1 /**< Allow another service to become the primary owner if requested */ #define DBUS_NAME_FLAG_REPLACE_EXISTING 0x2 /**< Request to replace the current primary owner */ diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h index 565eb832f2..b733a68856 100644 --- a/src/dbus/qdbusconnection_p.h +++ b/src/dbus/qdbusconnection_p.h @@ -260,6 +260,8 @@ private: QString getNameOwnerNoCache(const QString &service); + void watchForDBusDisconnection(); + void _q_newConnection(QDBusConnectionPrivate *newConnection); protected: @@ -279,6 +281,7 @@ private slots: void serviceOwnerChangedNoLock(const QString &name, const QString &oldOwner, const QString &newOwner); void registerServiceNoLock(const QString &serviceName); void unregisterServiceNoLock(const QString &serviceName); + void handleDBusDisconnection(); signals: void dispatchStatusChanged(); diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index 3be775db82..d0468f4af0 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -1121,6 +1121,12 @@ void QDBusConnectionPrivate::closeConnection() rootNode.children.clear(); // free resources } +void QDBusConnectionPrivate::handleDBusDisconnection() +{ + while (!pendingCalls.isEmpty()) + processFinishedCall(pendingCalls.first()); +} + void QDBusConnectionPrivate::checkThread() { Q_ASSERT(thread() == QDBusConnectionManager::instance()); @@ -1646,6 +1652,19 @@ void QDBusConnectionPrivate::handleSignal(const QDBusMessage& msg) handleSignal(key, msg); // third try } +void QDBusConnectionPrivate::watchForDBusDisconnection() +{ + SignalHook hook; + // Initialize the hook for Disconnected signal + hook.service.clear(); // org.freedesktop.DBus.Local.Disconnected uses empty service name + hook.path = QDBusUtil::dbusPathLocal(); + hook.obj = this; + hook.params << QMetaType::Void; + hook.midx = staticMetaObject.indexOfSlot("handleDBusDisconnection()"); + Q_ASSERT(hook.midx != -1); + signalHooks.insert(QLatin1String("Disconnected:" DBUS_INTERFACE_LOCAL), hook); +} + void QDBusConnectionPrivate::setServer(QDBusServer *object, DBusServer *s, const QDBusErrorInternal &error) { mode = ServerMode; @@ -1711,6 +1730,8 @@ void QDBusConnectionPrivate::setPeer(DBusConnection *c, const QDBusErrorInternal qDBusSignalFilter, this, 0); + watchForDBusDisconnection(); + QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection); } @@ -1787,6 +1808,8 @@ void QDBusConnectionPrivate::setConnection(DBusConnection *dbc, const QDBusError Q_ASSERT(hook.midx != -1); signalHooks.insert(QLatin1String("NameOwnerChanged:" DBUS_INTERFACE_DBUS), hook); + watchForDBusDisconnection(); + qDBusDebug() << this << ": connected successfully"; // schedule a dispatch: @@ -1813,10 +1836,16 @@ void QDBusConnectionPrivate::processFinishedCall(QDBusPendingCallPrivate *call) QDBusMessage &msg = call->replyMessage; if (call->pending) { - // decode the message - DBusMessage *reply = q_dbus_pending_call_steal_reply(call->pending); - msg = QDBusMessagePrivate::fromDBusMessage(reply, connection->capabilities); - q_dbus_message_unref(reply); + // when processFinishedCall is called and pending call is not completed, + // it means we received disconnected signal from libdbus + if (q_dbus_pending_call_get_completed(call->pending)) { + // decode the message + DBusMessage *reply = q_dbus_pending_call_steal_reply(call->pending); + msg = QDBusMessagePrivate::fromDBusMessage(reply, connection->capabilities); + q_dbus_message_unref(reply); + } else { + msg = QDBusMessage::createError(QDBusError::Disconnected, QDBusUtil::disconnectedErrorMessage()); + } } qDBusDebug() << connection << "got message reply:" << msg; @@ -2116,8 +2145,8 @@ void QDBusConnectionPrivate::sendInternal(QDBusPendingCallPrivate *pcall, void * pcall->pending = pending; q_dbus_pending_call_set_notify(pending, qDBusResultReceived, pcall, 0); - // DBus won't notify us when a peer disconnects so we need to track these ourselves - if (mode == QDBusConnectionPrivate::PeerMode) + // DBus won't notify us when a peer disconnects or server terminates so we need to track these ourselves + if (mode == QDBusConnectionPrivate::PeerMode || mode == QDBusConnectionPrivate::ClientMode) pendingCalls.append(pcall); return; diff --git a/src/dbus/qdbusutil_p.h b/src/dbus/qdbusutil_p.h index 8f5ae922db..f4ab9b9b1f 100644 --- a/src/dbus/qdbusutil_p.h +++ b/src/dbus/qdbusutil_p.h @@ -155,6 +155,8 @@ namespace QDBusUtil { return QStringLiteral(DBUS_SERVICE_DBUS); } inline QString dbusPath() { return QStringLiteral(DBUS_PATH_DBUS); } + inline QString dbusPathLocal() + { return QStringLiteral(DBUS_PATH_LOCAL); } inline QString dbusInterface() { // it's the same string, but just be sure |