Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qdbusmessage.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qdbusmessage.h"
6#include "qdbusmessage_p.h"
7
8#include <qdebug.h>
9#include <qstringlist.h>
10
11#include "qdbus_symbols_p.h"
12
13#include "qdbusargument_p.h"
14#include "qdbuserror.h"
15#include "qdbusmetatype.h"
16#include "qdbusconnection_p.h"
17#include "qdbusutil_p.h"
18
19#ifndef QT_NO_DBUS
20
22
23using namespace Qt::StringLiterals;
24
26
32
33static inline const char *data(const QByteArray &arr)
34{
35 return arr.isEmpty() ? nullptr : arr.constData();
36}
37
39 : localReply(nullptr), ref(1), type(QDBusMessage::InvalidMessage),
40 delayedReply(false), parametersValidated(false),
41 localMessage(false), autoStartService(true),
42 interactiveAuthorizationAllowed(false), isReplyRequired(false)
43{
44}
45
50
52{
54 qWarning("QDBusMessage: replying to a message that isn't a method call");
55 return;
56 }
57
58 if (call->localMessage) {
59 localMessage = true;
60 call->localReply = new QDBusMessage(*this); // keep an internal copy
61 } else {
62 serial = call->serial;
63 service = call->service;
64 }
65
66 // the reply must have a serial or be a local-loop optimization
68}
69
75{
76 if (d_ptr->type == ErrorMessage) {
77 if (!d_ptr->message.isEmpty())
78 return d_ptr->message;
79 if (!d_ptr->arguments.isEmpty())
80 return d_ptr->arguments.at(0).toString();
81 }
82 return QString();
83}
84
94DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message, QDBusConnection::ConnectionCapabilities capabilities,
96{
97 if (!qdbus_loadLibDBus()) {
98 *error = QDBusError(QDBusError::Failed, "Could not open lidbus-1 library"_L1);
99 return nullptr;
100 }
101
102 DBusMessage *msg = nullptr;
103 const QDBusMessagePrivate *d_ptr = message.d_ptr;
104
105 switch (d_ptr->type) {
107 //qDebug() << "QDBusMessagePrivate::toDBusMessage" << "message is invalid";
108 break;
110 // only service and interface can be empty -> path and name must not be empty
111 if (!d_ptr->parametersValidated) {
113 return nullptr;
115 return nullptr;
117 return nullptr;
119 return nullptr;
120 }
121
122 msg = q_dbus_message_new_method_call(data(d_ptr->service.toUtf8()), d_ptr->path.toUtf8(),
123 data(d_ptr->interface.toUtf8()), d_ptr->name.toUtf8());
124 q_dbus_message_set_auto_start( msg, d_ptr->autoStartService );
125 q_dbus_message_set_allow_interactive_authorization(msg, d_ptr->interactiveAuthorizationAllowed);
126
127 break;
129 msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
130 if (!d_ptr->localMessage) {
131 q_dbus_message_set_destination(msg, data(d_ptr->service.toUtf8()));
132 q_dbus_message_set_reply_serial(msg, d_ptr->serial);
133 }
134 break;
136 // error name can't be empty
137 if (!d_ptr->parametersValidated
139 return nullptr;
140
141 msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_ERROR);
142 q_dbus_message_set_error_name(msg, d_ptr->name.toUtf8());
143 if (!d_ptr->localMessage) {
144 q_dbus_message_set_destination(msg, data(d_ptr->service.toUtf8()));
145 q_dbus_message_set_reply_serial(msg, d_ptr->serial);
146 }
147 break;
149 // only the service name can be empty here
150 if (!d_ptr->parametersValidated) {
152 return nullptr;
154 return nullptr;
156 return nullptr;
158 return nullptr;
159 }
160
161 msg = q_dbus_message_new_signal(d_ptr->path.toUtf8(), d_ptr->interface.toUtf8(),
162 d_ptr->name.toUtf8());
163 q_dbus_message_set_destination(msg, data(d_ptr->service.toUtf8()));
164 break;
165 }
166
167 // if we got here, the parameters validated
168 // and since the message parameters cannot be changed once the message is created
169 // we can record this fact
170 d_ptr->parametersValidated = true;
171
172 QDBusMarshaller marshaller(capabilities);
173 q_dbus_message_iter_init_append(msg, &marshaller.iterator);
174 if (!d_ptr->message.isEmpty())
175 // prepend the error message
176 marshaller.append(d_ptr->message);
177 for (const QVariant &argument : std::as_const(d_ptr->arguments))
179
180 // check if everything is ok
181 if (marshaller.ok)
182 return msg;
183
184 // not ok;
185 q_dbus_message_unref(msg);
186 *error = QDBusError(QDBusError::Failed, "Marshalling failed: "_L1 + marshaller.errorString);
187 return nullptr;
188}
189
190/*
191struct DBusMessage
192{
193 DBusAtomic refcount;
194 DBusHeader header;
195 DBusString body;
196 char byte_order;
197 unsigned int locked : 1;
198DBUS_DISABLE_CHECKS
199 unsigned int in_cache : 1;
200#endif
201 DBusList *size_counters;
202 long size_counter_delta;
203 dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS;
204 DBusDataSlotList slot_list;
205#ifndef DBUS_DISABLE_CHECKS
206 int generation;
207#endif
208};
209*/
210
215QDBusMessage QDBusMessagePrivate::fromDBusMessage(DBusMessage *dmsg, QDBusConnection::ConnectionCapabilities capabilities)
216{
218 if (!dmsg)
219 return message;
220
221 message.d_ptr->type = QDBusMessage::MessageType(q_dbus_message_get_type(dmsg));
222 message.d_ptr->serial = q_dbus_message_get_serial(dmsg);
223 message.d_ptr->path = QString::fromUtf8(q_dbus_message_get_path(dmsg));
224 message.d_ptr->interface = QString::fromUtf8(q_dbus_message_get_interface(dmsg));
225 message.d_ptr->name = message.d_ptr->type == DBUS_MESSAGE_TYPE_ERROR ?
226 QString::fromUtf8(q_dbus_message_get_error_name(dmsg)) :
227 QString::fromUtf8(q_dbus_message_get_member(dmsg));
228 message.d_ptr->service = QString::fromUtf8(q_dbus_message_get_sender(dmsg));
229 message.d_ptr->signature = QString::fromUtf8(q_dbus_message_get_signature(dmsg));
230 message.d_ptr->interactiveAuthorizationAllowed = q_dbus_message_get_allow_interactive_authorization(dmsg);
231 message.d_ptr->isReplyRequired = !q_dbus_message_get_no_reply(dmsg);
232
233 QDBusDemarshaller demarshaller(capabilities);
234 demarshaller.message = q_dbus_message_ref(dmsg);
235 if (q_dbus_message_iter_init(demarshaller.message, &demarshaller.iterator))
236 while (!demarshaller.atEnd())
237 message << demarshaller.toVariantInternal();
238 return message;
239}
240
242{
243 return message.d_ptr->localMessage;
244}
245
247 const QDBusMessage &asSent)
248{
249 // simulate the message being sent to the bus and then received back
250 // the only field that the bus sets when delivering the message
251 // (as opposed to the message as we send it), is the sender
252 // so we simply set the sender to our unique name
253
254 // determine if we are carrying any complex types
255 QString computedSignature;
256 for (const QVariant &argument : std::as_const(asSent.d_ptr->arguments)) {
257 QMetaType id = argument.metaType();
259 if ((id.id() != QMetaType::QStringList && id.id() != QMetaType::QByteArray &&
260 qstrlen(signature) != 1) || id == QMetaType::fromType<QDBusVariant>()) {
261 // yes, we are
262 // we must marshall and demarshall again so as to create QDBusArgument
263 // entries for the complex types
265 DBusMessage *message = toDBusMessage(asSent, conn.connectionCapabilities(), &error);
266 if (!message) {
267 // failed to marshall, so it's a call error
269 }
270
271 q_dbus_message_set_sender(message, conn.baseService.toUtf8());
272
274 retval.d_ptr->localMessage = true;
275 q_dbus_message_unref(message);
276 if (retval.d_ptr->service.isEmpty())
277 retval.d_ptr->service = conn.baseService;
278 return retval;
279 } else {
280 computedSignature += QLatin1StringView(signature);
281 }
282 }
283
284 // no complex types seen
285 // optimize by using the variant list itself
286 QDBusMessage retval;
287 QDBusMessagePrivate *d = retval.d_ptr;
288 d->arguments = asSent.d_ptr->arguments;
289 d->path = asSent.d_ptr->path;
290 d->interface = asSent.d_ptr->interface;
291 d->name = asSent.d_ptr->name;
292 d->message = asSent.d_ptr->message;
293 d->type = asSent.d_ptr->type;
294
295 d->service = conn.baseService;
296 d->signature = computedSignature;
297 d->localMessage = true;
298 return retval;
299}
300
302 const QDBusMessage &callMsg)
303{
304 // simulate the reply (return or error) message being sent to the bus and
305 // then received back.
306 if (callMsg.d_ptr->localReply)
307 return makeLocal(conn, *callMsg.d_ptr->localReply);
308 return QDBusMessage(); // failed
309}
310
357 const QString &name)
358{
360 message.d_ptr->type = SignalMessage;
361 message.d_ptr->path = path;
362 message.d_ptr->interface = interface;
363 message.d_ptr->name = name;
364
365 return message;
366}
367
381 const QString &interface, const QString &name)
382{
384 message.d_ptr->type = SignalMessage;
385 message.d_ptr->service = service;
386 message.d_ptr->path = path;
387 message.d_ptr->interface = interface;
388 message.d_ptr->name = name;
389
390 return message;
391}
392
413 const QString &interface, const QString &method)
414{
416 message.d_ptr->type = MethodCallMessage;
417 message.d_ptr->service = service;
418 message.d_ptr->path = path;
419 message.d_ptr->interface = interface;
420 message.d_ptr->name = method;
421 message.d_ptr->isReplyRequired = true;
422
423 return message;
424}
425
431{
433 error.d_ptr->type = ErrorMessage;
434 error.d_ptr->name = name;
435 error.d_ptr->message = msg;
436
437 return error;
438}
439
460{
462 reply.setArguments(arguments);
463 reply.d_ptr->type = ReplyMessage;
464 reply.d_ptr->createResponseLink(d_ptr);
465 return reply;
466}
467
473{
475 reply.d_ptr->createResponseLink(d_ptr);
476 return reply;
477}
478
487
502{
504 msg.d_ptr->parametersValidated = true;
505 return msg;
506}
507
508
518
527{
528 d_ptr = other.d_ptr;
529 d_ptr->ref.ref();
530}
531
536{
537 if (!d_ptr->ref.deref())
538 delete d_ptr;
539}
540
549{
550 qAtomicAssign(d_ptr, other.d_ptr);
551 return *this;
552}
553
558{
559 if (d_ptr->type == ErrorMessage || d_ptr->type == ReplyMessage)
560 return QString(); // d_ptr->service holds the destination
561 return d_ptr->service;
562}
563
569{
570 return d_ptr->path;
571}
572
578{
579 return d_ptr->interface;
580}
581
586{
587 if (d_ptr->type != ErrorMessage)
588 return d_ptr->name;
589 return QString();
590}
591
596{
597 if (d_ptr->type == ErrorMessage)
598 return d_ptr->name;
599 return QString();
600}
601
607{
608 return d_ptr->signature;
609}
610
618{
619 // Only method calls can have replies
621 return false;
622
623 if (d_ptr->localMessage) // if it's a local message, reply is required
624 return true;
625 return d_ptr->isReplyRequired;
626}
627
643{
644 d_ptr->delayedReply = enable;
645}
646
653{
654 return d_ptr->delayedReply;
655}
656
681
692{
693 return d_ptr->autoStartService;
694}
695
724
738
745void QDBusMessage::setArguments(const QList<QVariant> &arguments)
746{
747 d_ptr->arguments = arguments;
748}
749
754QList<QVariant> QDBusMessage::arguments() const
755{
756 return d_ptr->arguments;
757}
758
765{
766 d_ptr->arguments.append(arg);
767 return *this;
768}
769
771 : d_ptr(&dd)
772{
773 d_ptr->ref.ref();
774}
775
780{
781 switch (d_ptr->type) {
783 return MethodCallMessage;
785 return ReplyMessage;
787 return ErrorMessage;
789 return SignalMessage;
790 default:
791 break;
792 }
793 return InvalidMessage;
794}
795
796#ifndef QT_NO_DEBUG_STREAM
798{
799 switch (t)
800 {
802 return dbg << "MethodCall";
804 return dbg << "MethodReturn";
806 return dbg << "Signal";
808 return dbg << "Error";
809 default:
810 return dbg << "Invalid";
811 }
812}
813
814static void debugVariantList(QDebug dbg, const QVariantList &list)
815{
816 bool first = true;
817 for (const QVariant &elem : list) {
818 if (!first)
819 dbg.nospace() << ", ";
820 dbg.nospace() << qPrintable(QDBusUtil::argumentToString(elem));
821 first = false;
822 }
823}
824
826{
827 QDebugStateSaver saver(dbg);
828 dbg.nospace() << "QDBusMessage(type=" << msg.type()
829 << ", service=" << msg.service();
832 dbg.nospace() << ", path=" << msg.path()
833 << ", interface=" << msg.interface()
834 << ", member=" << msg.member();
835 if (msg.type() == QDBusMessage::ErrorMessage)
836 dbg.nospace() << ", error name=" << msg.errorName()
837 << ", error message=" << msg.errorMessage();
838 dbg.nospace() << ", signature=" << msg.signature()
839 << ", contents=(";
840 debugVariantList(dbg, msg.arguments());
841 dbg.nospace() << ") )";
842 return dbg;
843}
844#endif
845
853
854#endif // QT_NO_DBUS
bool ref() noexcept
bool deref() noexcept
\inmodule QtCore
Definition qbytearray.h:57
QDBusConnection::ConnectionCapabilities connectionCapabilities() const
DBusMessageIter iterator
\inmodule QtDBus
Definition qdbuserror.h:21
static QString errorString(ErrorType error)
ErrorType
In order to facilitate verification of the most common D-Bus errors generated by the D-Bus implementa...
Definition qdbuserror.h:24
void append(uchar arg)
bool appendVariantInternal(const QVariant &arg)
DBusMessageIter iterator
QList< QVariant > arguments
static QDBusMessage fromDBusMessage(DBusMessage *dmsg, QDBusConnection::ConnectionCapabilities capabilities)
void createResponseLink(const QDBusMessagePrivate *call)
QDBusMessage * localReply
static QDBusMessage makeLocalReply(const QDBusConnectionPrivate &conn, const QDBusMessage &asSent)
static DBusMessage * toDBusMessage(const QDBusMessage &message, QDBusConnection::ConnectionCapabilities capabilities, QDBusError *error)
static bool isLocal(const QDBusMessage &msg)
static QDBusMessage makeLocal(const QDBusConnectionPrivate &conn, const QDBusMessage &asSent)
QDBusMessage::MessageType type
\inmodule QtDBus
static QDBusMessage createSignal(const QString &path, const QString &interface, const QString &name)
Constructs a new DBus message with the given path, interface and name, representing a signal emission...
QString errorName() const
Returns the name of the error that was received.
QDBusMessage()
Constructs an empty, invalid QDBusMessage object.
void setAutoStartService(bool enable)
Sets the auto start flag to enable.
QDBusMessage & operator<<(const QVariant &arg)
Appends the argument arg to the list of arguments to be sent over D-Bus in a method call or signal em...
QString service() const
Returns the name of the service or the bus address of the remote method call.
QDBusMessage createReply(const QList< QVariant > &arguments=QList< QVariant >()) const
Constructs a new DBus message representing a reply, with the given arguments.
void setInteractiveAuthorizationAllowed(bool enable)
Enables or disables the ALLOW_INTERACTIVE_AUTHORIZATION flag in a message.
bool isInteractiveAuthorizationAllowed() const
Returns whether the message has the ALLOW_INTERACTIVE_AUTHORIZATION flag set.
QList< QVariant > arguments() const
Returns the list of arguments that are going to be sent or were received from D-Bus.
friend class QDBusMessagePrivate
bool isReplyRequired() const
Returns the flag that indicates if this message should see a reply or not.
void setArguments(const QList< QVariant > &arguments)
Sets the arguments that are going to be sent over D-Bus to arguments.
QString interface() const
Returns the interface of the method being called (in the case of a method call) or of the signal bein...
bool autoStartService() const
Returns the auto start flag, as set by setAutoStartService().
static QDBusMessage createError(const QString &name, const QString &msg)
Constructs a new DBus message representing an error, with the given name and msg.
MessageType type() const
Returns the message type.
QString member() const
Returns the name of the signal that was emitted or the name of the method that was called.
static QDBusMessage createTargetedSignal(const QString &service, const QString &path, const QString &interface, const QString &name)
QString signature() const
Returns the signature of the signal that was received or for the output arguments of a method call.
QDBusMessage & operator=(QDBusMessage &&other) noexcept
bool isDelayedReply() const
Returns the delayed reply flag, as set by setDelayedReply().
MessageType
The possible message types:
QString errorMessage() const
void setDelayedReply(bool enable) const
Sets whether the message will be replied later (if enable is true) or if an automatic reply should be...
static QDBusMessage createMethodCall(const QString &destination, const QString &path, const QString &interface, const QString &method)
Constructs a new DBus message representing a method call.
QString path() const
Returns the path of the object that this message is being sent to (in the case of a method call) or b...
QDBusMessage createErrorReply(const QString &name, const QString &msg) const
Constructs a new DBus message representing an error reply message, with the given name and msg.
~QDBusMessage()
Disposes of the object and frees any resources that were being held.
static const char * typeToSignature(QMetaType type)
\inmodule QtCore
\inmodule QtCore
bool isEmpty() const noexcept
Definition qlist.h:401
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void append(parameter_type t)
Definition qlist.h:458
\inmodule QtCore
Definition qmetatype.h:341
QScopedPointer< QObjectData > d_ptr
Definition qobject.h:373
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
QByteArray toUtf8() const &
Definition qstring.h:634
\inmodule QtCore
Definition qvariant.h:65
QString toString() const
Returns the variant as a QString if the variant has a userType() including, but not limited to:
#define DBUS_MESSAGE_TYPE_METHOD_CALL
#define DBUS_MESSAGE_TYPE_ERROR
#define DBUS_MESSAGE_TYPE_METHOD_RETURN
#define DBUS_MESSAGE_TYPE_SIGNAL
#define DBUS_MESSAGE_TYPE_INVALID
QList< QVariant > arguments
bool checkInterfaceName(const QString &name, AllowEmptyFlag empty, QDBusError *error)
Definition qdbusutil_p.h:62
QString argumentToString(const QVariant &arg)
bool checkObjectPath(const QString &path, AllowEmptyFlag empty, QDBusError *error)
Definition qdbusutil_p.h:86
bool checkErrorName(const QString &name, AllowEmptyFlag empty, QDBusError *error)
@ EmptyNotAllowed
Definition qdbusutil_p.h:59
bool checkBusName(const QString &name, AllowEmptyFlag empty, QDBusError *error)
Definition qdbusutil_p.h:74
bool checkMemberName(const QString &name, AllowEmptyFlag empty, QDBusError *error, const char *nameType=nullptr)
Definition qdbusutil_p.h:98
Combined button and popup list for selecting options.
QT_WARNING_POP void qAtomicAssign(T *&d, T *x)
This is a helper for the assignment operators of implicitly shared classes.
Definition qatomic.h:180
size_t qstrlen(const char *str)
#define Q_UNLIKELY(x)
bool qdbus_loadLibDBus()
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char * interface
DBusConnection const char DBusError * error
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
static void debugVariantList(QDebug dbg, const QVariantList &list)
static QDebug operator<<(QDebug dbg, QDBusMessage::MessageType t)
#define qWarning
Definition qlogging.h:166
#define QT_IMPL_METATYPE_EXTERN(TYPE)
Definition qmetatype.h:1390
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum type
GLboolean enable
GLuint GLsizei const GLchar * message
GLint ref
GLuint name
GLint first
GLdouble GLdouble t
Definition qopenglext.h:243
GLsizei const GLchar *const * path
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
#define qPrintable(string)
Definition qstring.h:1531
QList< int > list
[14]
QObject::connect nullptr
QSharedPointer< T > other(t)
[5]
QNetworkReply * reply
QDBusArgument argument