1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
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 Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/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 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
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
76QT_BEGIN_NAMESPACE
77
78class QDBusMessage;
79class QSocketNotifier;
80class QTimerEvent;
81class QDBusObjectPrivate;
82class QDBusCallDeliveryEvent;
83class QDBusActivateObjectEvent;
84class QMetaMethod;
85class QDBusInterfacePrivate;
86struct QDBusMetaObject;
87class QDBusAbstractInterface;
88class QDBusConnectionInterface;
89class QDBusPendingCallPrivate;
90
91class QDBusErrorInternal
92{
93 mutable DBusError error;
94 Q_DISABLE_COPY(QDBusErrorInternal)
95public:
96 inline QDBusErrorInternal() { q_dbus_error_init(&error); }
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; }
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
106class QDBusConnectionPrivate: public QObject
107{
108 Q_OBJECT
109public:
110 // structs and enums
111 enum ConnectionMode { InvalidMode, ServerMode, ClientMode, PeerMode }; // LocalMode
112
113 struct Watcher
114 {
115 Watcher(): watch(0), read(0), write(0) {}
116 DBusWatch *watch;
117 QSocketNotifier *read;
118 QSocketNotifier *write;
119 };
120
121 struct SignalHook
122 {
123 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
141 inline ObjectTreeNode() : obj(0), flags(0) { }
142 inline ObjectTreeNode(const QString &n) // intentionally implicit
143 : name(n), obj(0), flags(0) { }
144 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
160public:
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 {
171 WatchedServiceData() : refcount(0) {}
172 WatchedServiceData(const QString &owner, int refcount = 0)
173 : owner(owner), refcount(refcount)
174 {}
175 QString owner;
176 int refcount;
177 };
178 typedef QHash<QString, WatchedServiceData> WatchedServicesHash;
179
180public:
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
225 inline void serverConnection(const QDBusConnection &connection)
226 { emit newServerConnection(connection); }
227
228private:
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
249protected:
250 void customEvent(QEvent *e);
251 void timerEvent(QTimerEvent *e);
252
253public 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
261private 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
266signals:
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
271public:
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
310public:
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
328 static QDBusConnectionPrivate *d(const QDBusConnection& q) { return q.d; }
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
338extern int qDBusParametersForMethod(const QMetaMethod &mm, QList<int>& metaTypes);
339extern int qDBusNameToTypeId(const char *name);
340extern bool qDBusCheckAsyncTag(const char *tag);
341extern bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name);
342extern QString qDBusInterfaceFromMetaObject(const QMetaObject *mo);
343
344// in qdbusinternalfilters.cpp
345extern QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode &node, const QString &path);
346extern QDBusMessage qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode &node,
347 const QDBusMessage &msg);
348extern QDBusMessage qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode &node,
349 const QDBusMessage &msg);
350extern QDBusMessage qDBusPropertyGetAll(const QDBusConnectionPrivate::ObjectTreeNode &node,
351 const QDBusMessage &msg);
352
353QT_END_NAMESPACE
354
355#endif // QT_NO_DBUS
356#endif
357