summaryrefslogtreecommitdiff
path: root/source/l/qt5/patches/qt5.qtbug-51649.patch
blob: 3b7cf9ec643f67c03c37ac66501a1b1fa885ebe7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
From acde2e69df5dedc624674107596f276125e22864 Mon Sep 17 00:00:00 2001
From: Weng Xuetian <wengxt@gmail.com>
Date: Thu, 3 Mar 2016 21:56:53 -0800
Subject: [PATCH] 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
---
 src/dbus/dbus_minimal_p.h                          |  2 ++
 src/dbus/qdbusintegrator.cpp                       | 26 +++++++++++++++++-----
 src/dbus/qdbusutil_p.h                             |  6 +++++
 .../dbus/qdbusconnection/tst_qdbusconnection.cpp   | 22 ++++++++++++++++++
 .../dbus/qdbusconnection/tst_qdbusconnection.h     |  1 +
 5 files changed, 51 insertions(+), 6 deletions(-)

diff --git a/src/dbus/dbus_minimal_p.h b/src/dbus/dbus_minimal_p.h
index f0a2954..8f25b24 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/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp
index cd44861..320419f 100644
--- a/src/dbus/qdbusintegrator.cpp
+++ b/src/dbus/qdbusintegrator.cpp
@@ -519,6 +519,14 @@ bool QDBusConnectionPrivate::handleMessage(const QDBusMessage &amsg)
     switch (amsg.type()) {
     case QDBusMessage::SignalMessage:
         handleSignal(amsg);
+        // Check local disconnected signal from libdbus
+        if (amsg.interface() == QDBusUtil::dbusInterfaceLocal()
+            && amsg.path() == QDBusUtil::dbusPathLocal()
+            && amsg.member() == QDBusUtil::disconnected()
+            && !QDBusMessagePrivate::isLocal(amsg)) {
+            while (!pendingCalls.isEmpty())
+                processFinishedCall(pendingCalls.first());
+        }
         // if there are any other filters in this DBusConnection,
         // let them see the signal too
         return false;
@@ -1767,10 +1775,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;
 
@@ -2070,8 +2084,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 8f5ae92..ca70ff9 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
@@ -165,8 +167,12 @@ namespace QDBusUtil
     { return QStringLiteral(DBUS_INTERFACE_PROPERTIES); }
     inline QString dbusInterfaceIntrospectable()
     { return QStringLiteral(DBUS_INTERFACE_INTROSPECTABLE); }
+    inline QString dbusInterfaceLocal()
+    { return QStringLiteral(DBUS_INTERFACE_LOCAL); }
     inline QString nameOwnerChanged()
     { return QStringLiteral("NameOwnerChanged"); }
+    inline QString disconnected()
+    { return QStringLiteral("Disconnected"); }
     inline QString disconnectedErrorMessage()
     { return QStringLiteral("Not connected to D-Bus server"); }
 }
diff --git a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp
index e91f87d..6c7e6b1 100644
--- a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp
+++ b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp
@@ -1218,6 +1218,28 @@ void tst_QDBusConnection::callVirtualObjectLocal()
     QCOMPARE(obj.replyArguments, subPathReply.arguments());
 }
 
+void tst_QDBusConnection::pendingCallWhenDisconnected()
+{
+    QDBusServer *server = new QDBusServer;
+    QDBusConnection con = QDBusConnection::connectToPeer(server->address(), "disconnect");
+    QTestEventLoop::instance().enterLoop(2);
+    QVERIFY(!QTestEventLoop::instance().timeout());
+    QVERIFY(con.isConnected());
+
+    delete server;
+
+    // Make sure we call the method before we know it is disconnected.
+    QVERIFY(con.isConnected());
+    QDBusMessage message = QDBusMessage::createMethodCall("", "/", QString(), "method");
+    QDBusPendingCall reply = con.asyncCall(message);
+
+    QTestEventLoop::instance().enterLoop(2);
+    QVERIFY(!con.isConnected());
+    QVERIFY(reply.isFinished());
+    QVERIFY(reply.isError());
+    QVERIFY(reply.error().type() == QDBusError::Disconnected);
+}
+
 QString MyObject::path;
 QString MyObjectWithoutInterface::path;
 QString MyObjectWithoutInterface::interface;
diff --git a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.h b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.h
index a53ba32..720e484 100644
--- a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.h
+++ b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.h
@@ -121,6 +121,7 @@ private slots:
     void registerVirtualObject();
     void callVirtualObject();
     void callVirtualObjectLocal();
+    void pendingCallWhenDisconnected();
 
 public:
     QString serviceName() const { return "org.qtproject.Qt.Autotests.QDBusConnection"; }
-- 
2.7.1