1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDBus module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qdbusmessage.h"
43 #include "qdbusmessage_p.h"
46 #include <qstringlist.h>
48 #include "qdbus_symbols_p.h"
50 #include "qdbusargument_p.h"
51 #include "qdbuserror.h"
52 #include "qdbusmetatype.h"
53 #include "qdbusconnection_p.h"
54 #include "qdbusutil_p.h"
60 static inline const char *data(const QByteArray &arr)
62 return arr.isEmpty() ? 0 : arr.constData();
65 QDBusMessagePrivate::QDBusMessagePrivate()
66 : msg(0), reply(0), type(DBUS_MESSAGE_TYPE_INVALID),
67 timeout(-1), localReply(0), ref(1), delayedReply(false), localMessage(false),
68 parametersValidated(false), autoStartService(true)
72 QDBusMessagePrivate::~QDBusMessagePrivate()
75 q_dbus_message_unref(msg);
77 q_dbus_message_unref(reply);
83 Returns the human-readable message associated with the error that was received.
85 QString QDBusMessage::errorMessage() const
87 if (d_ptr->type == ErrorMessage) {
88 if (!d_ptr->message.isEmpty())
89 return d_ptr->message;
90 if (!d_ptr->arguments.isEmpty())
91 return d_ptr->arguments.at(0).toString();
98 Constructs a DBusMessage object from \a message. The returned value must be de-referenced
99 with q_dbus_message_unref. The \a capabilities flags indicates which capabilities to use.
101 The \a error object is set to indicate the error if anything went wrong with the
102 marshalling. Usually, this error message will be placed in the reply, as if the call failed.
103 The \a error pointer must not be null.
105 DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message, QDBusConnection::ConnectionCapabilities capabilities,
108 if (!qdbus_loadLibDBus()) {
109 *error = QDBusError(QDBusError::Failed, QLatin1String("Could not open lidbus-1 library"));
113 DBusMessage *msg = 0;
114 const QDBusMessagePrivate *d_ptr = message.d_ptr;
116 switch (d_ptr->type) {
117 case DBUS_MESSAGE_TYPE_INVALID:
118 //qDebug() << "QDBusMessagePrivate::toDBusMessage" << "message is invalid";
120 case DBUS_MESSAGE_TYPE_METHOD_CALL:
121 // only service and interface can be empty -> path and name must not be empty
122 if (!d_ptr->parametersValidated) {
123 if (!QDBusUtil::checkBusName(d_ptr->service, QDBusUtil::EmptyAllowed, error))
125 if (!QDBusUtil::checkObjectPath(d_ptr->path, QDBusUtil::EmptyNotAllowed, error))
127 if (!QDBusUtil::checkInterfaceName(d_ptr->interface, QDBusUtil::EmptyAllowed, error))
129 if (!QDBusUtil::checkMemberName(d_ptr->name, QDBusUtil::EmptyNotAllowed, error, "method"))
133 msg = q_dbus_message_new_method_call(data(d_ptr->service.toUtf8()), d_ptr->path.toUtf8(),
134 data(d_ptr->interface.toUtf8()), d_ptr->name.toUtf8());
135 q_dbus_message_set_auto_start( msg, d_ptr->autoStartService );
137 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
138 msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
139 if (!d_ptr->localMessage) {
140 q_dbus_message_set_destination(msg, q_dbus_message_get_sender(d_ptr->reply));
141 q_dbus_message_set_reply_serial(msg, q_dbus_message_get_serial(d_ptr->reply));
144 case DBUS_MESSAGE_TYPE_ERROR:
145 // error name can't be empty
146 if (!d_ptr->parametersValidated
147 && !QDBusUtil::checkErrorName(d_ptr->name, QDBusUtil::EmptyNotAllowed, error))
150 msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_ERROR);
151 q_dbus_message_set_error_name(msg, d_ptr->name.toUtf8());
152 if (!d_ptr->localMessage) {
153 q_dbus_message_set_destination(msg, q_dbus_message_get_sender(d_ptr->reply));
154 q_dbus_message_set_reply_serial(msg, q_dbus_message_get_serial(d_ptr->reply));
157 case DBUS_MESSAGE_TYPE_SIGNAL:
158 // nothing can be empty here
159 if (!d_ptr->parametersValidated) {
160 if (!QDBusUtil::checkObjectPath(d_ptr->path, QDBusUtil::EmptyNotAllowed, error))
162 if (!QDBusUtil::checkInterfaceName(d_ptr->interface, QDBusUtil::EmptyAllowed, error))
164 if (!QDBusUtil::checkMemberName(d_ptr->name, QDBusUtil::EmptyNotAllowed, error, "method"))
168 msg = q_dbus_message_new_signal(d_ptr->path.toUtf8(), d_ptr->interface.toUtf8(),
169 d_ptr->name.toUtf8());
176 // if we got here, the parameters validated
177 // and since the message parameters cannot be changed once the message is created
178 // we can record this fact
179 d_ptr->parametersValidated = true;
181 QDBusMarshaller marshaller(capabilities);
182 QVariantList::ConstIterator it = d_ptr->arguments.constBegin();
183 QVariantList::ConstIterator cend = d_ptr->arguments.constEnd();
184 q_dbus_message_iter_init_append(msg, &marshaller.iterator);
185 if (!d_ptr->message.isEmpty())
186 // prepend the error message
187 marshaller.append(d_ptr->message);
188 for ( ; it != cend; ++it)
189 marshaller.appendVariantInternal(*it);
191 // check if everything is ok
196 q_dbus_message_unref(msg);
197 *error = QDBusError(QDBusError::Failed, QLatin1String("Marshalling failed: ") + marshaller.errorString);
208 unsigned int locked : 1;
210 unsigned int in_cache : 1;
212 DBusList *size_counters;
213 long size_counter_delta;
214 dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS;
215 DBusDataSlotList slot_list;
216 #ifndef DBUS_DISABLE_CHECKS
224 Constructs a QDBusMessage by parsing the given DBusMessage object.
226 QDBusMessage QDBusMessagePrivate::fromDBusMessage(DBusMessage *dmsg, QDBusConnection::ConnectionCapabilities capabilities)
228 QDBusMessage message;
232 message.d_ptr->type = q_dbus_message_get_type(dmsg);
233 message.d_ptr->path = QString::fromUtf8(q_dbus_message_get_path(dmsg));
234 message.d_ptr->interface = QString::fromUtf8(q_dbus_message_get_interface(dmsg));
235 message.d_ptr->name = message.d_ptr->type == DBUS_MESSAGE_TYPE_ERROR ?
236 QString::fromUtf8(q_dbus_message_get_error_name(dmsg)) :
237 QString::fromUtf8(q_dbus_message_get_member(dmsg));
238 message.d_ptr->service = QString::fromUtf8(q_dbus_message_get_sender(dmsg));
239 message.d_ptr->signature = QString::fromUtf8(q_dbus_message_get_signature(dmsg));
240 message.d_ptr->msg = q_dbus_message_ref(dmsg);
242 QDBusDemarshaller demarshaller(capabilities);
243 demarshaller.message = q_dbus_message_ref(dmsg);
244 if (q_dbus_message_iter_init(demarshaller.message, &demarshaller.iterator))
245 while (!demarshaller.atEnd())
246 message << demarshaller.toVariantInternal();
250 bool QDBusMessagePrivate::isLocal(const QDBusMessage &message)
252 return message.d_ptr->localMessage;
255 QDBusMessage QDBusMessagePrivate::makeLocal(const QDBusConnectionPrivate &conn,
256 const QDBusMessage &asSent)
258 // simulate the message being sent to the bus and then received back
259 // the only field that the bus sets when delivering the message
260 // (as opposed to the message as we send it), is the sender
261 // so we simply set the sender to our unique name
263 // determine if we are carrying any complex types
264 QString computedSignature;
265 QVariantList::ConstIterator it = asSent.d_ptr->arguments.constBegin();
266 QVariantList::ConstIterator end = asSent.d_ptr->arguments.constEnd();
267 for ( ; it != end; ++it) {
268 int id = it->userType();
269 const char *signature = QDBusMetaType::typeToSignature(id);
270 if ((id != QVariant::StringList && id != QVariant::ByteArray &&
271 qstrlen(signature) != 1) || id == qMetaTypeId<QDBusVariant>()) {
273 // we must marshall and demarshall again so as to create QDBusArgument
274 // entries for the complex types
276 DBusMessage *message = toDBusMessage(asSent, conn.capabilities, &error);
278 // failed to marshall, so it's a call error
279 return QDBusMessage::createError(error);
282 q_dbus_message_set_sender(message, conn.baseService.toUtf8());
284 QDBusMessage retval = fromDBusMessage(message, conn.capabilities);
285 retval.d_ptr->localMessage = true;
286 q_dbus_message_unref(message);
287 if (retval.d_ptr->service.isEmpty())
288 retval.d_ptr->service = conn.baseService;
291 computedSignature += QLatin1String(signature);
295 // no complex types seen
296 // optimize by using the variant list itself
298 QDBusMessagePrivate *d = retval.d_ptr;
299 d->arguments = asSent.d_ptr->arguments;
300 d->path = asSent.d_ptr->path;
301 d->interface = asSent.d_ptr->interface;
302 d->name = asSent.d_ptr->name;
303 d->message = asSent.d_ptr->message;
304 d->type = asSent.d_ptr->type;
306 d->service = conn.baseService;
307 d->signature = computedSignature;
308 d->localMessage = true;
312 QDBusMessage QDBusMessagePrivate::makeLocalReply(const QDBusConnectionPrivate &conn,
313 const QDBusMessage &callMsg)
315 // simulate the reply (return or error) message being sent to the bus and
316 // then received back.
317 if (callMsg.d_ptr->localReply)
318 return makeLocal(conn, *callMsg.d_ptr->localReply);
319 return QDBusMessage(); // failed
327 \brief The QDBusMessage class represents one message sent or
328 received over the D-Bus bus.
330 This object can represent any of the four different types of
331 messages (MessageType) that can occur on the bus:
335 \li Method return values
340 Objects of this type are created with the static createError(),
341 createMethodCall() and createSignal() functions. Use the
342 QDBusConnection::send() function to send the messages.
346 \enum QDBusMessage::MessageType
347 The possible message types:
349 \value MethodCallMessage a message representing an outgoing or incoming method call
350 \value SignalMessage a message representing an outgoing or incoming signal emission
351 \value ReplyMessage a message representing the return values of a method call
352 \value ErrorMessage a message representing an error condition in response to a method call
353 \value InvalidMessage an invalid message: this is never set on messages received from D-Bus
357 Constructs a new DBus message with the given \a path, \a interface
358 and \a name, representing a signal emission.
360 A DBus signal is emitted from one application and is received by
361 all applications that are listening for that signal from that
364 The QDBusMessage object that is returned can be sent using the
365 QDBusConnection::send() function.
367 QDBusMessage QDBusMessage::createSignal(const QString &path, const QString &interface,
370 QDBusMessage message;
371 message.d_ptr->type = DBUS_MESSAGE_TYPE_SIGNAL;
372 message.d_ptr->path = path;
373 message.d_ptr->interface = interface;
374 message.d_ptr->name = name;
380 Constructs a new DBus message representing a method call.
381 A method call always informs its destination address
382 (\a service, \a path, \a interface and \a method).
384 The DBus bus allows calling a method on a given remote object without specifying the
385 destination interface, if the method name is unique. However, if two interfaces on the
386 remote object export the same method name, the result is undefined (one of the two may be
387 called or an error may be returned).
389 When using DBus in a peer-to-peer context (i.e., not on a bus), the \a service parameter is
392 The QDBusInterface class provides a simpler abstraction to synchronous
395 This function returns a QDBusMessage object that can be sent with
396 QDBusConnection::call().
398 QDBusMessage QDBusMessage::createMethodCall(const QString &service, const QString &path,
399 const QString &interface, const QString &method)
401 QDBusMessage message;
402 message.d_ptr->type = DBUS_MESSAGE_TYPE_METHOD_CALL;
403 message.d_ptr->service = service;
404 message.d_ptr->path = path;
405 message.d_ptr->interface = interface;
406 message.d_ptr->name = method;
412 Constructs a new DBus message representing an error,
413 with the given \a name and \a msg.
415 QDBusMessage QDBusMessage::createError(const QString &name, const QString &msg)
418 error.d_ptr->type = DBUS_MESSAGE_TYPE_ERROR;
419 error.d_ptr->name = name;
420 error.d_ptr->message = msg;
426 \fn QDBusMessage QDBusMessage::createError(const QDBusError &error)
428 Constructs a new DBus message representing the given \a error.
432 \fn QDBusMessage QDBusMessage::createError(QDBusError::ErrorType type, const QString &msg)
434 Constructs a new DBus message for the error type \a type using
435 the message \a msg. Returns the DBus message.
439 \fn QDBusMessage QDBusMessage::createReply(const QList<QVariant> &arguments) const
441 Constructs a new DBus message representing a reply, with the given
444 QDBusMessage QDBusMessage::createReply(const QVariantList &arguments) const
447 reply.setArguments(arguments);
448 reply.d_ptr->type = DBUS_MESSAGE_TYPE_METHOD_RETURN;
450 reply.d_ptr->reply = q_dbus_message_ref(d_ptr->msg);
451 if (d_ptr->localMessage) {
452 reply.d_ptr->localMessage = true;
453 d_ptr->localReply = new QDBusMessage(reply); // keep an internal copy
456 // the reply must have a msg or be a local-loop optimization
457 Q_ASSERT(reply.d_ptr->reply || reply.d_ptr->localMessage);
462 Constructs a new DBus message representing an error reply message,
463 with the given \a name and \a msg.
465 QDBusMessage QDBusMessage::createErrorReply(const QString name, const QString &msg) const
467 QDBusMessage reply = QDBusMessage::createError(name, msg);
469 reply.d_ptr->reply = q_dbus_message_ref(d_ptr->msg);
470 if (d_ptr->localMessage) {
471 reply.d_ptr->localMessage = true;
472 d_ptr->localReply = new QDBusMessage(reply); // keep an internal copy
475 // the reply must have a msg or be a local-loop optimization
476 Q_ASSERT(reply.d_ptr->reply || reply.d_ptr->localMessage);
481 \fn QDBusMessage QDBusMessage::createReply(const QVariant &argument) const
483 Constructs a new DBus message representing a reply, with the
488 \fn QDBusMessage QDBusMessage::createErrorReply(const QDBusError &error) const
490 Constructs a new DBus message representing an error reply message,
491 from the given \a error object.
495 \fn QDBusMessage QDBusMessage::createErrorReply(QDBusError::ErrorType type, const QString &msg) const
497 Constructs a new DBus reply message for the error type \a type using
498 the message \a msg. Returns the DBus message.
500 QDBusMessage QDBusMessage::createErrorReply(QDBusError::ErrorType atype, const QString &amsg) const
502 QDBusMessage msg = createErrorReply(QDBusError::errorString(atype), amsg);
503 msg.d_ptr->parametersValidated = true;
509 Constructs an empty, invalid QDBusMessage object.
511 \sa createError(), createMethodCall(), createSignal()
513 QDBusMessage::QDBusMessage()
515 d_ptr = new QDBusMessagePrivate;
519 Constructs a copy of the object given by \a other.
521 Note: QDBusMessage objects are shared. Modifications made to the
522 copy will affect the original one as well. See setDelayedReply()
523 for more information.
525 QDBusMessage::QDBusMessage(const QDBusMessage &other)
532 Disposes of the object and frees any resources that were being held.
534 QDBusMessage::~QDBusMessage()
536 if (!d_ptr->ref.deref())
541 Copies the contents of the object given by \a other.
543 Note: QDBusMessage objects are shared. Modifications made to the
544 copy will affect the original one as well. See setDelayedReply()
545 for more information.
547 QDBusMessage &QDBusMessage::operator=(const QDBusMessage &other)
549 qAtomicAssign(d_ptr, other.d_ptr);
554 Returns the name of the service or the bus address of the remote method call.
556 QString QDBusMessage::service() const
558 return d_ptr->service;
562 Returns the path of the object that this message is being sent to (in the case of a
563 method call) or being received from (for a signal).
565 QString QDBusMessage::path() const
571 Returns the interface of the method being called (in the case of a method call) or of
572 the signal being received from.
574 QString QDBusMessage::interface() const
576 return d_ptr->interface;
580 Returns the name of the signal that was emitted or the name of the method that was called.
582 QString QDBusMessage::member() const
584 if (d_ptr->type != ErrorMessage)
590 Returns the name of the error that was received.
592 QString QDBusMessage::errorName() const
594 if (d_ptr->type == ErrorMessage)
600 Returns the signature of the signal that was received or for the output arguments
603 QString QDBusMessage::signature() const
605 return d_ptr->signature;
609 Returns the flag that indicates if this message should see a reply
610 or not. This is only meaningful for \l {MethodCallMessage}{method
611 call messages}: any other kind of message cannot have replies and
612 this function will always return false for them.
614 bool QDBusMessage::isReplyRequired() const
617 return d_ptr->localMessage; // if it's a local message, reply is required
618 return !q_dbus_message_get_no_reply(d_ptr->msg);
622 Sets whether the message will be replied later (if \a enable is
623 true) or if an automatic reply should be generated by QtDBus
624 (if \a enable is false).
626 In D-Bus, all method calls must generate a reply to the caller, unless the
627 caller explicitly indicates otherwise (see isReplyRequired()). QtDBus
628 automatically generates such replies for any slots being called, but it
629 also allows slots to indicate whether they will take responsibility
630 of sending the reply at a later time, after the function has finished
633 \sa {Delayed Replies}
635 void QDBusMessage::setDelayedReply(bool enable) const
637 d_ptr->delayedReply = enable;
641 Returns the delayed reply flag, as set by setDelayedReply(). By default, this
642 flag is false, which means QtDBus will generate automatic replies
645 bool QDBusMessage::isDelayedReply() const
647 return d_ptr->delayedReply;
651 Sets the auto start flag to \a enable. This flag only makes sense
652 for method call messages, where it tells the D-Bus server to
653 either auto start the service responsible for the service name, or
654 not to auto start it.
656 By default this flag is true, i.e. a service is autostarted.
659 When the service that this method call is sent to is already
660 running, the method call is sent to it. If the service is not
661 running yet, the D-Bus daemon is requested to autostart the
662 service that is assigned to this service name. This is
663 handled by .service files that are placed in a directory known
664 to the D-Bus server. These files then each contain a service
665 name and the path to a program that should be executed when
666 this service name is requested.
670 void QDBusMessage::setAutoStartService(bool enable)
672 d_ptr->autoStartService = enable;
676 Returns the auto start flag, as set by setAutoStartService(). By default, this
677 flag is true, which means QtDBus will auto start a service, if it is
680 \sa setAutoStartService()
684 bool QDBusMessage::autoStartService() const
686 return d_ptr->autoStartService;
690 Sets the arguments that are going to be sent over D-Bus to \a arguments. Those
691 will be the arguments to a method call or the parameters in the signal.
695 void QDBusMessage::setArguments(const QList<QVariant> &arguments)
697 // FIXME: should we detach?
698 d_ptr->arguments = arguments;
702 Returns the list of arguments that are going to be sent or were received from
705 QList<QVariant> QDBusMessage::arguments() const
707 return d_ptr->arguments;
711 Appends the argument \a arg to the list of arguments to be sent over D-Bus in
712 a method call or signal emission.
715 QDBusMessage &QDBusMessage::operator<<(const QVariant &arg)
717 // FIXME: should we detach?
718 d_ptr->arguments.append(arg);
723 Returns the message type.
725 QDBusMessage::MessageType QDBusMessage::type() const
727 switch (d_ptr->type) {
728 case DBUS_MESSAGE_TYPE_METHOD_CALL:
729 return MethodCallMessage;
730 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
732 case DBUS_MESSAGE_TYPE_ERROR:
734 case DBUS_MESSAGE_TYPE_SIGNAL:
735 return SignalMessage;
739 return InvalidMessage;
743 Sends the message without waiting for a reply. This is suitable
744 for errors, signals, and return values as well as calls whose
745 return values are not necessary.
747 Returns true if the message was queued successfully;
748 otherwise returns false.
750 \sa QDBusConnection::send()
752 #ifndef QT_NO_DEBUG_STREAM
753 static QDebug operator<<(QDebug dbg, QDBusMessage::MessageType t)
757 case QDBusMessage::MethodCallMessage:
758 return dbg << "MethodCall";
759 case QDBusMessage::ReplyMessage:
760 return dbg << "MethodReturn";
761 case QDBusMessage::SignalMessage:
762 return dbg << "Signal";
763 case QDBusMessage::ErrorMessage:
764 return dbg << "Error";
766 return dbg << "Invalid";
770 static void debugVariantList(QDebug dbg, const QVariantList &list)
773 QVariantList::ConstIterator it = list.constBegin();
774 QVariantList::ConstIterator end = list.constEnd();
775 for ( ; it != end; ++it) {
777 dbg.nospace() << ", ";
778 dbg.nospace() << qPrintable(QDBusUtil::argumentToString(*it));
783 QDebug operator<<(QDebug dbg, const QDBusMessage &msg)
785 dbg.nospace() << "QDBusMessage(type=" << msg.type()
786 << ", service=" << msg.service();
787 if (msg.type() == QDBusMessage::MethodCallMessage ||
788 msg.type() == QDBusMessage::SignalMessage)
789 dbg.nospace() << ", path=" << msg.path()
790 << ", interface=" << msg.interface()
791 << ", member=" << msg.member();
792 if (msg.type() == QDBusMessage::ErrorMessage)
793 dbg.nospace() << ", error name=" << msg.errorName()
794 << ", error message=" << msg.errorMessage();
795 dbg.nospace() << ", signature=" << msg.signature()
797 debugVariantList(dbg, msg.arguments());
798 dbg.nospace() << ") )";