1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtDBus module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 //
43 //  W A R N I N G
44 //  -------------
45 //
46 // This file is not part of the public API.  This header file may
47 // change from version to version without notice, or even be
48 // removed.
49 //
50 // We mean it.
51 //
52 //
53 
54 #ifndef QDBUSCONNECTION_P_H
55 #define QDBUSCONNECTION_P_H
56 
57 #include <qdbuserror.h>
58 #include <qdbusconnection.h>
59 
60 #include <QtCore/qatomic.h>
61 #include <QtCore/qhash.h>
62 #include <QtCore/qmutex.h>
63 #include <QtCore/qobject.h>
64 #include <QtCore/qpointer.h>
65 #include <QtCore/qreadwritelock.h>
66 #include <QtCore/qstringlist.h>
67 #include <QtCore/qvarlengtharray.h>
68 #include <QtCore/qvector.h>
69 
70 #include "qdbus_symbols_p.h"
71 
72 #include <qdbusmessage.h>
73 
74 #ifndef QT_NO_DBUS
75 
76 QT_BEGIN_NAMESPACE
77 
78 class QDBusMessage;
79 class QSocketNotifier;
80 class QTimerEvent;
81 class QDBusObjectPrivate;
82 class QDBusCallDeliveryEvent;
83 class QDBusActivateObjectEvent;
84 class QMetaMethod;
85 class QDBusInterfacePrivate;
86 struct QDBusMetaObject;
87 class QDBusAbstractInterface;
88 class QDBusConnectionInterface;
89 class QDBusPendingCallPrivate;
90 
91 class QDBusErrorInternal
92 {
93     mutable DBusError error;
Q_DISABLE_COPY(QDBusErrorInternal)94     Q_DISABLE_COPY(QDBusErrorInternal)
95 public:
96     inline QDBusErrorInternal() { q_dbus_error_init(&error); }
~QDBusErrorInternal()97     inline ~QDBusErrorInternal() { q_dbus_error_free(&error); }
98     inline bool operator !() const { return !q_dbus_error_is_set(&error); }
99     inline operator DBusError *() { q_dbus_error_free(&error); return &error; }
QDBusError()100     inline operator QDBusError() const { QDBusError err(&error); q_dbus_error_free(&error); return err; }
101 };
102 
103 // QDBusConnectionPrivate holds the DBusConnection and
104 // can have many QDBusConnection objects referring to it
105 
106 class QDBusConnectionPrivate: public QObject
107 {
108     Q_OBJECT
109 public:
110     // structs and enums
111     enum ConnectionMode { InvalidMode, ServerMode, ClientMode, PeerMode }; // LocalMode
112 
113     struct Watcher
114     {
WatcherWatcher115         Watcher(): watch(0), read(0), write(0) {}
116         DBusWatch *watch;
117         QSocketNotifier *read;
118         QSocketNotifier *write;
119     };
120 
121     struct SignalHook
122     {
SignalHookSignalHook123         inline SignalHook() : obj(0), midx(-1) { }
124         QString service, path, signature;
125         QObject* obj;
126         int midx;
127         QList<int> params;
128         QStringList argumentMatch;
129         QByteArray matchRule;
130     };
131 
132     enum TreeNodeType {
133         Object = 0x0,
134         VirtualObject = 0x01000000
135     };
136 
137     struct ObjectTreeNode
138     {
139         typedef QVector<ObjectTreeNode> DataList;
140 
ObjectTreeNodeObjectTreeNode141         inline ObjectTreeNode() : obj(0), flags(0) { }
ObjectTreeNodeObjectTreeNode142         inline ObjectTreeNode(const QString &n) // intentionally implicit
143             : name(n), obj(0), flags(0) { }
~ObjectTreeNodeObjectTreeNode144         inline ~ObjectTreeNode() { }
145         inline bool operator<(const QString &other) const
146             { return name < other; }
147         inline bool operator<(const QStringRef &other) const
148             { return QStringRef(&name) < other; }
149 
150         QString name;
151         union {
152             QObject *obj;
153             QDBusVirtualObject *treeNode;
154         };
155         int flags;
156 
157         DataList children;
158     };
159 
160 public:
161     // typedefs
162     typedef QMultiHash<int, Watcher> WatcherHash;
163     typedef QHash<int, DBusTimeout *> TimeoutHash;
164     typedef QList<QPair<DBusTimeout *, int> > PendingTimeoutList;
165 
166     typedef QMultiHash<QString, SignalHook> SignalHookHash;
167     typedef QHash<QString, QDBusMetaObject* > MetaObjectHash;
168     typedef QHash<QByteArray, int> MatchRefCountHash;
169 
170     struct WatchedServiceData {
WatchedServiceDataWatchedServiceData171         WatchedServiceData() : refcount(0) {}
172         WatchedServiceData(const QString &owner, int refcount = 0)
ownerWatchedServiceData173             : owner(owner), refcount(refcount)
174         {}
175         QString owner;
176         int refcount;
177     };
178     typedef QHash<QString, WatchedServiceData> WatchedServicesHash;
179 
180 public:
181     // public methods are entry points from other objects
182     explicit QDBusConnectionPrivate(QObject *parent = 0);
183     ~QDBusConnectionPrivate();
184     void deleteYourself();
185 
186     void setBusService(const QDBusConnection &connection);
187     void setPeer(DBusConnection *connection, const QDBusErrorInternal &error);
188     void setConnection(DBusConnection *connection, const QDBusErrorInternal &error);
189     void setServer(DBusServer *server, const QDBusErrorInternal &error);
190     void closeConnection();
191 
192     QString getNameOwner(const QString &service);
193 
194     int send(const QDBusMessage &message);
195     QDBusMessage sendWithReply(const QDBusMessage &message, int mode, int timeout = -1);
196     QDBusMessage sendWithReplyLocal(const QDBusMessage &message);
197     QDBusPendingCallPrivate *sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
198                                                 const char *returnMethod, const char *errorMethod,int timeout = -1);
199     bool connectSignal(const QString &service, const QString &path, const QString& interface,
200                        const QString &name, const QStringList &argumentMatch, const QString &signature,
201                        QObject *receiver, const char *slot);
202     void connectSignal(const QString &key, const SignalHook &hook);
203     SignalHookHash::Iterator disconnectSignal(SignalHookHash::Iterator &it);
204     bool disconnectSignal(const QString &service, const QString &path, const QString& interface,
205                           const QString &name, const QStringList &argumentMatch, const QString &signature,
206                           QObject *receiver, const char *slot);
207     void registerObject(const ObjectTreeNode *node);
208     void connectRelay(const QString &service,
209                       const QString &path, const QString &interface,
210                       QDBusAbstractInterface *receiver, const char *signal);
211     void disconnectRelay(const QString &service,
212                          const QString &path, const QString &interface,
213                          QDBusAbstractInterface *receiver, const char *signal);
214     void registerService(const QString &serviceName);
215     void unregisterService(const QString &serviceName);
216 
217     bool handleMessage(const QDBusMessage &msg);
218     void waitForFinished(QDBusPendingCallPrivate *pcall);
219 
220     QDBusMetaObject *findMetaObject(const QString &service, const QString &path,
221                                     const QString &interface, QDBusError &error);
222 
223     void postEventToThread(int action, QObject *target, QEvent *event);
224 
serverConnection(const QDBusConnection & connection)225     inline void serverConnection(const QDBusConnection &connection)
226         { emit newServerConnection(connection); }
227 
228 private:
229     void checkThread();
230     bool handleError(const QDBusErrorInternal &error);
231 
232     void handleSignal(const QString &key, const QDBusMessage &msg);
233     void handleSignal(const QDBusMessage &msg);
234     void handleObjectCall(const QDBusMessage &message);
235 
236     void activateSignal(const SignalHook& hook, const QDBusMessage &msg);
237     void activateObject(ObjectTreeNode &node, const QDBusMessage &msg, int pathStartPos);
238     bool activateInternalFilters(const ObjectTreeNode &node, const QDBusMessage &msg);
239     bool activateCall(QObject *object, int flags, const QDBusMessage &msg);
240 
241     void sendError(const QDBusMessage &msg, QDBusError::ErrorType code);
242     void deliverCall(QObject *object, int flags, const QDBusMessage &msg,
243                      const QList<int> &metaTypes, int slotIdx);
244 
245     bool isServiceRegisteredByThread(const QString &serviceName) const;
246 
247     QString getNameOwnerNoCache(const QString &service);
248 
249 protected:
250     void customEvent(QEvent *e);
251     void timerEvent(QTimerEvent *e);
252 
253 public slots:
254     // public slots
255     void doDispatch();
256     void socketRead(int);
257     void socketWrite(int);
258     void objectDestroyed(QObject *o);
259     void relaySignal(QObject *obj, const QMetaObject *, int signalId, const QVariantList &args);
260 
261 private slots:
262     void serviceOwnerChangedNoLock(const QString &name, const QString &oldOwner, const QString &newOwner);
263     void registerServiceNoLock(const QString &serviceName);
264     void unregisterServiceNoLock(const QString &serviceName);
265 
266 signals:
267     void serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
268     void callWithCallbackFailed(const QDBusError &error, const QDBusMessage &message);
269     void newServerConnection(const QDBusConnection &connection);
270 
271 public:
272     QAtomicInt ref;
273     QDBusConnection::ConnectionCapabilities capabilities;
274     QString name;               // this connection's name
275     QString baseService;        // this connection's base service
276     QStringList serverConnectionNames;
277 
278     ConnectionMode mode;
279 
280     // members accessed in unlocked mode (except for deletion)
281     // connection and server provide their own locking mechanisms
282     // busService doesn't have state to be changed
283     DBusConnection *connection;
284     DBusServer *server;
285     QDBusConnectionInterface *busService;
286 
287     // watchers and timeouts are accessed from any thread
288     // but the corresponding timer and QSocketNotifier must be handled
289     // only in the object's thread
290     QMutex watchAndTimeoutLock;
291     WatcherHash watchers;
292     TimeoutHash timeouts;
293     PendingTimeoutList timeoutsPendingAdd;
294 
295     // members accessed through a lock
296     QMutex dispatchLock;
297     QReadWriteLock lock;
298     QDBusError lastError;
299 
300     QStringList serviceNames;
301     WatchedServicesHash watchedServices;
302     SignalHookHash signalHooks;
303     MatchRefCountHash matchRefCounts;
304     ObjectTreeNode rootNode;
305     MetaObjectHash cachedMetaObjects;
306 
307     QMutex callDeliveryMutex;
308     QDBusCallDeliveryEvent *callDeliveryState; // protected by the callDeliveryMutex mutex
309 
310 public:
311     // static methods
312     static int findSlot(QObject *obj, const QByteArray &normalizedName, QList<int>& params);
313     static bool prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key,
314                             const QString &service,
315                             const QString &path, const QString &interface, const QString &name,
316                             const QStringList &argMatch,
317                             QObject *receiver, const char *signal, int minMIdx,
318                             bool buildSignature);
319     static DBusHandlerResult messageFilter(DBusConnection *, DBusMessage *, void *);
320     static bool checkReplyForDelivery(QDBusConnectionPrivate *target, QObject *object,
321                                       int idx, const QList<int> &metaTypes,
322                                       const QDBusMessage &msg);
323     static QDBusCallDeliveryEvent *prepareReply(QDBusConnectionPrivate *target, QObject *object,
324                                                 int idx, const QList<int> &metaTypes,
325                                                 const QDBusMessage &msg);
326     static void processFinishedCall(QDBusPendingCallPrivate *call);
327 
d(const QDBusConnection & q)328     static QDBusConnectionPrivate *d(const QDBusConnection& q) { return q.d; }
q(QDBusConnectionPrivate * connection)329     static QDBusConnection q(QDBusConnectionPrivate *connection) { return QDBusConnection(connection); }
330 
331     static void setSender(const QDBusConnectionPrivate *s);
332 
333     friend class QDBusActivateObjectEvent;
334     friend class QDBusCallDeliveryEvent;
335 };
336 
337 // in qdbusmisc.cpp
338 extern int qDBusParametersForMethod(const QMetaMethod &mm, QList<int>& metaTypes);
339 extern int qDBusNameToTypeId(const char *name);
340 extern bool qDBusCheckAsyncTag(const char *tag);
341 extern bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name);
342 extern QString qDBusInterfaceFromMetaObject(const QMetaObject *mo);
343 
344 // in qdbusinternalfilters.cpp
345 extern QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode &node, const QString &path);
346 extern QDBusMessage qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode &node,
347                                      const QDBusMessage &msg);
348 extern QDBusMessage qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode &node,
349                                      const QDBusMessage &msg);
350 extern QDBusMessage qDBusPropertyGetAll(const QDBusConnectionPrivate::ObjectTreeNode &node,
351                                         const QDBusMessage &msg);
352 
353 QT_END_NAMESPACE
354 
355 #endif // QT_NO_DBUS
356 #endif
357