Qt 6.x
The Qt SDK
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 : msg(nullptr), reply(nullptr), localReply(nullptr), ref(1), type(QDBusMessage::InvalidMessage),
40 delayedReply(false), localMessage(false),
41 parametersValidated(false), autoStartService(true),
42 interactiveAuthorizationAllowed(false)
43{
44}
45
47{
48 if (msg)
49 q_dbus_message_unref(msg);
50 if (reply)
51 q_dbus_message_unref(reply);
52 delete localReply;
53}
54
60{
61 if (d_ptr->type == ErrorMessage) {
62 if (!d_ptr->message.isEmpty())
63 return d_ptr->message;
64 if (!d_ptr->arguments.isEmpty())
65 return d_ptr->arguments.at(0).toString();
66 }
67 return QString();
68}
69
79DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message, QDBusConnection::ConnectionCapabilities capabilities,
81{
82 if (!qdbus_loadLibDBus()) {
83 *error = QDBusError(QDBusError::Failed, "Could not open lidbus-1 library"_L1);
84 return nullptr;
85 }
86
87 DBusMessage *msg = nullptr;
88 const QDBusMessagePrivate *d_ptr = message.d_ptr;
89
90 switch (d_ptr->type) {
92 //qDebug() << "QDBusMessagePrivate::toDBusMessage" << "message is invalid";
93 break;
95 // only service and interface can be empty -> path and name must not be empty
96 if (!d_ptr->parametersValidated) {
98 return nullptr;
100 return nullptr;
102 return nullptr;
104 return nullptr;
105 }
106
107 msg = q_dbus_message_new_method_call(data(d_ptr->service.toUtf8()), d_ptr->path.toUtf8(),
108 data(d_ptr->interface.toUtf8()), d_ptr->name.toUtf8());
109 q_dbus_message_set_auto_start( msg, d_ptr->autoStartService );
110 q_dbus_message_set_allow_interactive_authorization(msg, d_ptr->interactiveAuthorizationAllowed);
111
112 break;
114 msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
115 if (!d_ptr->localMessage) {
116 q_dbus_message_set_destination(msg, q_dbus_message_get_sender(d_ptr->reply));
117 q_dbus_message_set_reply_serial(msg, q_dbus_message_get_serial(d_ptr->reply));
118 }
119 break;
121 // error name can't be empty
122 if (!d_ptr->parametersValidated
124 return nullptr;
125
126 msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_ERROR);
127 q_dbus_message_set_error_name(msg, d_ptr->name.toUtf8());
128 if (!d_ptr->localMessage) {
129 q_dbus_message_set_destination(msg, q_dbus_message_get_sender(d_ptr->reply));
130 q_dbus_message_set_reply_serial(msg, q_dbus_message_get_serial(d_ptr->reply));
131 }
132 break;
134 // only the service name can be empty here
135 if (!d_ptr->parametersValidated) {
137 return nullptr;
139 return nullptr;
141 return nullptr;
143 return nullptr;
144 }
145
146 msg = q_dbus_message_new_signal(d_ptr->path.toUtf8(), d_ptr->interface.toUtf8(),
147 d_ptr->name.toUtf8());
148 q_dbus_message_set_destination(msg, data(d_ptr->service.toUtf8()));
149 break;
150 }
151
152 // if we got here, the parameters validated
153 // and since the message parameters cannot be changed once the message is created
154 // we can record this fact
155 d_ptr->parametersValidated = true;
156
157 QDBusMarshaller marshaller(capabilities);
158 q_dbus_message_iter_init_append(msg, &marshaller.iterator);
159 if (!d_ptr->message.isEmpty())
160 // prepend the error message
161 marshaller.append(d_ptr->message);
162 for (const QVariant &argument : std::as_const(d_ptr->arguments))
164
165 // check if everything is ok
166 if (marshaller.ok)
167 return msg;
168
169 // not ok;
170 q_dbus_message_unref(msg);
171 *error = QDBusError(QDBusError::Failed, "Marshalling failed: "_L1 + marshaller.errorString);
172 return nullptr;
173}
174
175/*
176struct DBusMessage
177{
178 DBusAtomic refcount;
179 DBusHeader header;
180 DBusString body;
181 char byte_order;
182 unsigned int locked : 1;
183DBUS_DISABLE_CHECKS
184 unsigned int in_cache : 1;
185#endif
186 DBusList *size_counters;
187 long size_counter_delta;
188 dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS;
189 DBusDataSlotList slot_list;
190#ifndef DBUS_DISABLE_CHECKS
191 int generation;
192#endif
193};
194*/
195
200QDBusMessage QDBusMessagePrivate::fromDBusMessage(DBusMessage *dmsg, QDBusConnection::ConnectionCapabilities capabilities)
201{
203 if (!dmsg)
204 return message;
205
206 message.d_ptr->type = QDBusMessage::MessageType(q_dbus_message_get_type(dmsg));
207 message.d_ptr->path = QString::fromUtf8(q_dbus_message_get_path(dmsg));
208 message.d_ptr->interface = QString::fromUtf8(q_dbus_message_get_interface(dmsg));
209 message.d_ptr->name = message.d_ptr->type == DBUS_MESSAGE_TYPE_ERROR ?
210 QString::fromUtf8(q_dbus_message_get_error_name(dmsg)) :
211 QString::fromUtf8(q_dbus_message_get_member(dmsg));
212 message.d_ptr->service = QString::fromUtf8(q_dbus_message_get_sender(dmsg));
213 message.d_ptr->signature = QString::fromUtf8(q_dbus_message_get_signature(dmsg));
214 message.d_ptr->interactiveAuthorizationAllowed = q_dbus_message_get_allow_interactive_authorization(dmsg);
215 message.d_ptr->msg = q_dbus_message_ref(dmsg);
216
217 QDBusDemarshaller demarshaller(capabilities);
218 demarshaller.message = q_dbus_message_ref(dmsg);
219 if (q_dbus_message_iter_init(demarshaller.message, &demarshaller.iterator))
220 while (!demarshaller.atEnd())
221 message << demarshaller.toVariantInternal();
222 return message;
223}
224
226{
227 return message.d_ptr->localMessage;
228}
229
231 const QDBusMessage &asSent)
232{
233 // simulate the message being sent to the bus and then received back
234 // the only field that the bus sets when delivering the message
235 // (as opposed to the message as we send it), is the sender
236 // so we simply set the sender to our unique name
237
238 // determine if we are carrying any complex types
239 QString computedSignature;
240 for (const QVariant &argument : std::as_const(asSent.d_ptr->arguments)) {
241 QMetaType id = argument.metaType();
243 if ((id.id() != QMetaType::QStringList && id.id() != QMetaType::QByteArray &&
244 qstrlen(signature) != 1) || id == QMetaType::fromType<QDBusVariant>()) {
245 // yes, we are
246 // we must marshall and demarshall again so as to create QDBusArgument
247 // entries for the complex types
249 DBusMessage *message = toDBusMessage(asSent, conn.connectionCapabilities(), &error);
250 if (!message) {
251 // failed to marshall, so it's a call error
253 }
254
255 q_dbus_message_set_sender(message, conn.baseService.toUtf8());
256
258 retval.d_ptr->localMessage = true;
259 q_dbus_message_unref(message);
260 if (retval.d_ptr->service.isEmpty())
261 retval.d_ptr->service = conn.baseService;
262 return retval;
263 } else {
264 computedSignature += QLatin1StringView(signature);
265 }
266 }
267
268 // no complex types seen
269 // optimize by using the variant list itself
270 QDBusMessage retval;
271 QDBusMessagePrivate *d = retval.d_ptr;
272 d->arguments = asSent.d_ptr->arguments;
273 d->path = asSent.d_ptr->path;
274 d->interface = asSent.d_ptr->interface;
275 d->name = asSent.d_ptr->name;
276 d->message = asSent.d_ptr->message;
277 d->type = asSent.d_ptr->type;
278
279 d->service = conn.baseService;
280 d->signature = computedSignature;
281 d->localMessage = true;
282 return retval;
283}
284
286 const QDBusMessage &callMsg)
287{
288 // simulate the reply (return or error) message being sent to the bus and
289 // then received back.
290 if (callMsg.d_ptr->localReply)
291 return makeLocal(conn, *callMsg.d_ptr->localReply);
292 return QDBusMessage(); // failed
293}
294
341 const QString &name)
342{
344 message.d_ptr->type = SignalMessage;
345 message.d_ptr->path = path;
346 message.d_ptr->interface = interface;
347 message.d_ptr->name = name;
348
349 return message;
350}
351
365 const QString &interface, const QString &name)
366{
368 message.d_ptr->type = SignalMessage;
369 message.d_ptr->service = service;
370 message.d_ptr->path = path;
371 message.d_ptr->interface = interface;
372 message.d_ptr->name = name;
373
374 return message;
375}
376
397 const QString &interface, const QString &method)
398{
400 message.d_ptr->type = MethodCallMessage;
401 message.d_ptr->service = service;
402 message.d_ptr->path = path;
403 message.d_ptr->interface = interface;
404 message.d_ptr->name = method;
405
406 return message;
407}
408
414{
416 error.d_ptr->type = ErrorMessage;
417 error.d_ptr->name = name;
418 error.d_ptr->message = msg;
419
420 return error;
421}
422
443{
445 reply.setArguments(arguments);
446 reply.d_ptr->type = ReplyMessage;
447 if (d_ptr->msg)
448 reply.d_ptr->reply = q_dbus_message_ref(d_ptr->msg);
449 if (d_ptr->localMessage) {
450 reply.d_ptr->localMessage = true;
451 d_ptr->localReply = new QDBusMessage(reply); // keep an internal copy
452 }
453
454 // the reply must have a msg or be a local-loop optimization
455 Q_ASSERT(reply.d_ptr->reply || reply.d_ptr->localMessage);
456 return reply;
457}
458
464{
466 if (d_ptr->msg)
467 reply.d_ptr->reply = q_dbus_message_ref(d_ptr->msg);
468 if (d_ptr->localMessage) {
469 reply.d_ptr->localMessage = true;
470 d_ptr->localReply = new QDBusMessage(reply); // keep an internal copy
471 }
472
473 // the reply must have a msg or be a local-loop optimization
474 Q_ASSERT(reply.d_ptr->reply || reply.d_ptr->localMessage);
475 return reply;
476}
477
483{
484 return createReply(QList{argument});
485}
486
501{
503 msg.d_ptr->parametersValidated = true;
504 return msg;
505}
506
507
514{
515 d_ptr = new QDBusMessagePrivate;
516}
517
526{
527 d_ptr = other.d_ptr;
528 d_ptr->ref.ref();
529}
530
535{
536 if (!d_ptr->ref.deref())
537 delete d_ptr;
538}
539
548{
549 qAtomicAssign(d_ptr, other.d_ptr);
550 return *this;
551}
552
557{
558 return d_ptr->service;
559}
560
566{
567 return d_ptr->path;
568}
569
575{
576 return d_ptr->interface;
577}
578
583{
584 if (d_ptr->type != ErrorMessage)
585 return d_ptr->name;
586 return QString();
587}
588
593{
594 if (d_ptr->type == ErrorMessage)
595 return d_ptr->name;
596 return QString();
597}
598
604{
605 return d_ptr->signature;
606}
607
615{
616 // Only method calls can have replies
618 return false;
619
620 if (!d_ptr->msg)
621 return d_ptr->localMessage; // if it's a local message, reply is required
622 return !q_dbus_message_get_no_reply(d_ptr->msg);
623}
624
640{
641 d_ptr->delayedReply = enable;
642}
643
650{
651 return d_ptr->delayedReply;
652}
653
675{
676 d_ptr->autoStartService = enable;
677}
678
689{
690 return d_ptr->autoStartService;
691}
692
712{
714}
715
727{
729}
730
738{
739 d_ptr->arguments = arguments;
740}
741
747{
748 return d_ptr->arguments;
749}
750
757{
758 d_ptr->arguments.append(arg);
759 return *this;
760}
761
766{
767 switch (d_ptr->type) {
769 return MethodCallMessage;
771 return ReplyMessage;
773 return ErrorMessage;
775 return SignalMessage;
776 default:
777 break;
778 }
779 return InvalidMessage;
780}
781
782#ifndef QT_NO_DEBUG_STREAM
784{
785 switch (t)
786 {
788 return dbg << "MethodCall";
790 return dbg << "MethodReturn";
792 return dbg << "Signal";
794 return dbg << "Error";
795 default:
796 return dbg << "Invalid";
797 }
798}
799
800static void debugVariantList(QDebug dbg, const QVariantList &list)
801{
802 bool first = true;
803 for (const QVariant &elem : list) {
804 if (!first)
805 dbg.nospace() << ", ";
806 dbg.nospace() << qPrintable(QDBusUtil::argumentToString(elem));
807 first = false;
808 }
809}
810
812{
813 QDebugStateSaver saver(dbg);
814 dbg.nospace() << "QDBusMessage(type=" << msg.type()
815 << ", service=" << msg.service();
818 dbg.nospace() << ", path=" << msg.path()
819 << ", interface=" << msg.interface()
820 << ", member=" << msg.member();
821 if (msg.type() == QDBusMessage::ErrorMessage)
822 dbg.nospace() << ", error name=" << msg.errorName()
823 << ", error message=" << msg.errorMessage();
824 dbg.nospace() << ", signature=" << msg.signature()
825 << ", contents=(";
826 debugVariantList(dbg, msg.arguments());
827 dbg.nospace() << ") )";
828 return dbg;
829}
830#endif
831
839
840#endif // QT_NO_DBUS
bool ref() noexcept
bool deref() noexcept
\inmodule QtCore
Definition qbytearray.h:57
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:106
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)
QDBusMessage * localReply
static QDBusMessage makeLocalReply(const QDBusConnectionPrivate &conn, const QDBusMessage &asSent)
static DBusMessage * toDBusMessage(const QDBusMessage &message, QDBusConnection::ConnectionCapabilities capabilities, QDBusError *error)
DBusMessage * reply
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)
Sets the interactive authorization flag to enable.
bool isInteractiveAuthorizationAllowed() const
Returns the interactive authorization allowed flag, as set by setInteractiveAuthorizationAllowed().
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:390
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void append(parameter_type t)
Definition qlist.h:441
\inmodule QtCore
Definition qmetatype.h:320
QScopedPointer< QObjectData > d_ptr
Definition qobject.h:338
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
QByteArray toUtf8() const &
Definition qstring.h:563
\inmodule QtCore
Definition qvariant.h:64
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)
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 QT_IMPL_METATYPE_EXTERN(TYPE)
Definition qmetatype.h:1369
GLenum type
GLboolean enable
GLuint GLsizei const GLchar * message
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
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:1391
QList< int > list
[14]
QObject::connect nullptr
QSharedPointer< T > other(t)
[5]
QNetworkReply * reply
QDBusArgument argument