diff options
Diffstat (limited to 'src/dbus')
-rw-r--r-- | src/dbus/dbus.pro | 6 | ||||
-rw-r--r-- | src/dbus/qdbus_symbols_p.h | 26 | ||||
-rw-r--r-- | src/dbus/qdbusabstractinterface.cpp | 9 | ||||
-rw-r--r-- | src/dbus/qdbusargument.cpp | 28 | ||||
-rw-r--r-- | src/dbus/qdbusargument.h | 4 | ||||
-rw-r--r-- | src/dbus/qdbusargument_p.h | 8 | ||||
-rw-r--r-- | src/dbus/qdbusconnection.cpp | 93 | ||||
-rw-r--r-- | src/dbus/qdbusconnection.h | 2 | ||||
-rw-r--r-- | src/dbus/qdbusconnection_p.h | 2 | ||||
-rw-r--r-- | src/dbus/qdbusconnectionmanager_p.h | 88 | ||||
-rw-r--r-- | src/dbus/qdbusdemarshaller.cpp | 17 | ||||
-rw-r--r-- | src/dbus/qdbusintegrator.cpp | 122 | ||||
-rw-r--r-- | src/dbus/qdbusintegrator_p.h | 9 | ||||
-rw-r--r-- | src/dbus/qdbusmarshaller.cpp | 24 | ||||
-rw-r--r-- | src/dbus/qdbusmetatype.cpp | 16 | ||||
-rw-r--r-- | src/dbus/qdbusmetatype_p.h | 1 | ||||
-rw-r--r-- | src/dbus/qdbusserver.cpp | 25 | ||||
-rw-r--r-- | src/dbus/qdbusserver.h | 3 | ||||
-rw-r--r-- | src/dbus/qdbusunixfiledescriptor.cpp | 316 | ||||
-rw-r--r-- | src/dbus/qdbusunixfiledescriptor.h | 103 | ||||
-rw-r--r-- | src/dbus/qdbusutil.cpp | 100 | ||||
-rw-r--r-- | src/dbus/qdbusutil_p.h | 4 |
22 files changed, 898 insertions, 108 deletions
diff --git a/src/dbus/dbus.pro b/src/dbus/dbus.pro index 52ed217..08c9ea1 100644 --- a/src/dbus/dbus.pro +++ b/src/dbus/dbus.pro @@ -59,7 +59,8 @@ HEADERS += $$PUB_HEADERS \ qdbusintegrator_p.h \ qdbuspendingcall_p.h \ qdbus_symbols_p.h \ - qdbusservicewatcher.h + qdbusservicewatcher.h \ + qdbusunixfiledescriptor.h SOURCES += qdbusconnection.cpp \ qdbusconnectioninterface.cpp \ qdbuserror.cpp \ @@ -85,4 +86,5 @@ SOURCES += qdbusconnection.cpp \ qdbuspendingcall.cpp \ qdbuspendingreply.cpp \ qdbus_symbols.cpp \ - qdbusservicewatcher.cpp + qdbusservicewatcher.cpp \ + qdbusunixfiledescriptor.cpp diff --git a/src/dbus/qdbus_symbols_p.h b/src/dbus/qdbus_symbols_p.h index c5f55af..039657e 100644 --- a/src/dbus/qdbus_symbols_p.h +++ b/src/dbus/qdbus_symbols_p.h @@ -296,6 +296,12 @@ DEFINEFUNC(dbus_bool_t , dbus_message_set_sender, (DBusMessage *message, DEFINEFUNC(void , dbus_message_unref, (DBusMessage *message), (message), ) +/* dbus-misc.h */ +DEFINEFUNC(void , dbus_get_version , (int *major_version_p, + int *minor_version_p, + int *micro_version_p), + (major_version_p, minor_version_p, micro_version_p), ) + /* dbus-pending-call.h */ DEFINEFUNC(dbus_bool_t , dbus_pending_call_set_notify, (DBusPendingCall *pending, DBusPendingCallNotifyFunction function, @@ -352,21 +358,17 @@ DEFINEFUNC(dbus_bool_t , dbus_server_set_watch_functions, (DBusServer DEFINEFUNC(void , dbus_server_unref, (DBusServer *server), (server), ) -/* dbus-signature.h */ -DEFINEFUNC(dbus_bool_t , dbus_signature_validate, (const char *signature, - DBusError *error), - (signature, error), return) -DEFINEFUNC(dbus_bool_t , dbus_signature_validate_single, (const char *signature, - DBusError *error), - (signature, error), return) -DEFINEFUNC(dbus_bool_t , dbus_type_is_basic, (int typecode), - (typecode), return) -DEFINEFUNC(dbus_bool_t , dbus_type_is_fixed, (int typecode), - (typecode), return) - /* dbus-thread.h */ DEFINEFUNC(dbus_bool_t , dbus_threads_init_default, (), (), return) + +/* D-Bus 1.4 symbols */ +#if !defined(QT_LINKED_LIBDBUS) || (DBUS_VERSION >= 0x010400) +DEFINEFUNC(dbus_bool_t , dbus_connection_can_send_type , (DBusConnection *connection, + int type), + (connection, type), return) +#endif + QT_END_NAMESPACE #endif // QT_NO_DBUS diff --git a/src/dbus/qdbusabstractinterface.cpp b/src/dbus/qdbusabstractinterface.cpp index e48e1c0..9e82c09 100644 --- a/src/dbus/qdbusabstractinterface.cpp +++ b/src/dbus/qdbusabstractinterface.cpp @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE static QDBusError checkIfValid(const QString &service, const QString &path, - const QString &interface, bool isDynamic) + const QString &interface, bool isDynamic, bool isPeer) { // We should be throwing exceptions here... oh well QDBusError error; @@ -69,7 +69,7 @@ static QDBusError checkIfValid(const QString &service, const QString &path, // use assertion here because this should never happen, at all Q_ASSERT_X(!interface.isEmpty(), "QDBusAbstractInterface", "Interface name cannot be empty"); } - if (!QDBusUtil::checkBusName(service, isDynamic ? QDBusUtil::EmptyNotAllowed : QDBusUtil::EmptyAllowed, &error)) + if (!QDBusUtil::checkBusName(service, (isDynamic && !isPeer) ? QDBusUtil::EmptyNotAllowed : QDBusUtil::EmptyAllowed, &error)) return error; if (!QDBusUtil::checkObjectPath(path, isDynamic ? QDBusUtil::EmptyNotAllowed : QDBusUtil::EmptyAllowed, &error)) return error; @@ -86,7 +86,8 @@ QDBusAbstractInterfacePrivate::QDBusAbstractInterfacePrivate(const QString &serv const QDBusConnection& con, bool isDynamic) : connection(con), service(serv), path(p), interface(iface), - lastError(checkIfValid(serv, p, iface, isDynamic)), + lastError(checkIfValid(serv, p, iface, isDynamic, (connectionPrivate() && + connectionPrivate()->mode == QDBusConnectionPrivate::PeerMode))), isValid(!lastError.isValid()) { if (!isValid) @@ -107,7 +108,7 @@ bool QDBusAbstractInterfacePrivate::canMakeCalls() const { // recheck only if we have a wildcard (i.e. empty) service or path // if any are empty, set the error message according to QDBusUtil - if (service.isEmpty()) + if (service.isEmpty() && connectionPrivate()->mode != QDBusConnectionPrivate::PeerMode) return QDBusUtil::checkBusName(service, QDBusUtil::EmptyNotAllowed, &lastError); if (path.isEmpty()) return QDBusUtil::checkObjectPath(path, QDBusUtil::EmptyNotAllowed, &lastError); diff --git a/src/dbus/qdbusargument.cpp b/src/dbus/qdbusargument.cpp index 09f0e82..806b7fe 100644 --- a/src/dbus/qdbusargument.cpp +++ b/src/dbus/qdbusargument.cpp @@ -487,6 +487,20 @@ QDBusArgument &QDBusArgument::operator<<(const QDBusSignature &arg) /*! \overload + \since 4.8 + \internal + Appends the primitive value \a arg of type \c{UNIX_FILE_DESCRIPTOR} (Unix + File Descriptor) to the D-Bus stream. +*/ +QDBusArgument &QDBusArgument::operator<<(const QDBusUnixFileDescriptor &arg) +{ + if (QDBusArgumentPrivate::checkWrite(d)) + d->marshaller()->append(arg); + return *this; +} + +/*! + \overload Appends the primitive value \a arg of type \c{VARIANT} to the D-Bus stream. A D-Bus variant type can contain any type, including other @@ -729,6 +743,20 @@ const QDBusArgument &QDBusArgument::operator>>(QDBusSignature &arg) const /*! \overload + \since 4.8 + \internal + Extracts one D-Bus primitive argument of type \c{UNIX_FILE_DESCRIPTOR} + (Unix file descriptor) from the D-Bus stream. +*/ +const QDBusArgument &QDBusArgument::operator>>(QDBusUnixFileDescriptor &arg) const +{ + if (QDBusArgumentPrivate::checkReadAndDetach(d)) + arg = d->demarshaller()->toUnixFileDescriptor(); + return *this; +} + +/*! + \overload Extracts one D-Bus primitive argument of type \c{VARIANT} from the D-Bus stream. diff --git a/src/dbus/qdbusargument.h b/src/dbus/qdbusargument.h index e331d8f..f80723e 100644 --- a/src/dbus/qdbusargument.h +++ b/src/dbus/qdbusargument.h @@ -61,6 +61,8 @@ QT_BEGIN_NAMESPACE QT_MODULE(DBus) +class QDBusUnixFileDescriptor; + class QDBusArgumentPrivate; class QDBusDemarshaller; class QDBusMarshaller; @@ -96,6 +98,7 @@ public: QDBusArgument &operator<<(const QDBusVariant &arg); QDBusArgument &operator<<(const QDBusObjectPath &arg); QDBusArgument &operator<<(const QDBusSignature &arg); + QDBusArgument &operator<<(const QDBusUnixFileDescriptor &arg); QDBusArgument &operator<<(const QStringList &arg); QDBusArgument &operator<<(const QByteArray &arg); @@ -127,6 +130,7 @@ public: const QDBusArgument &operator>>(QDBusVariant &arg) const; const QDBusArgument &operator>>(QDBusObjectPath &arg) const; const QDBusArgument &operator>>(QDBusSignature &arg) const; + const QDBusArgument &operator>>(QDBusUnixFileDescriptor &arg) const; const QDBusArgument &operator>>(QStringList &arg) const; const QDBusArgument &operator>>(QByteArray &arg) const; diff --git a/src/dbus/qdbusargument_p.h b/src/dbus/qdbusargument_p.h index 89a383f..1c713a3 100644 --- a/src/dbus/qdbusargument_p.h +++ b/src/dbus/qdbusargument_p.h @@ -54,10 +54,16 @@ // #include <qdbusargument.h> +#include "qdbusunixfiledescriptor.h" #include "qdbus_symbols_p.h" #ifndef QT_NO_DBUS +#ifndef DBUS_TYPE_UNIX_FD +# define DBUS_TYPE_UNIX_FD int('h') +# define DBUS_TYPE_UNIX_FD_AS_STRING "h" +#endif + QT_BEGIN_NAMESPACE class QDBusMarshaller; @@ -117,6 +123,7 @@ public: void append(const QString &arg); void append(const QDBusObjectPath &arg); void append(const QDBusSignature &arg); + void append(const QDBusUnixFileDescriptor &arg); void append(const QStringList &arg); void append(const QByteArray &arg); bool append(const QDBusVariant &arg); // this one can fail @@ -172,6 +179,7 @@ public: QString toString(); QDBusObjectPath toObjectPath(); QDBusSignature toSignature(); + QDBusUnixFileDescriptor toUnixFileDescriptor(); QDBusVariant toVariant(); QStringList toStringList(); QByteArray toByteArray(); diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp index 4883a4d..c8cf6ea 100644 --- a/src/dbus/qdbusconnection.cpp +++ b/src/dbus/qdbusconnection.cpp @@ -52,6 +52,7 @@ #include "qdbusconnection_p.h" #include "qdbusinterface_p.h" #include "qdbusutil_p.h" +#include "qdbusconnectionmanager_p.h" #include "qdbusthreaddebug_p.h" @@ -59,27 +60,6 @@ QT_BEGIN_NAMESPACE -class QDBusConnectionManager -{ -public: - QDBusConnectionManager() {} - ~QDBusConnectionManager(); - - QDBusConnectionPrivate *connection(const QString &name) const; - void removeConnection(const QString &name); - void setConnection(const QString &name, QDBusConnectionPrivate *c); - - QDBusConnectionPrivate *sender() const; - void setSender(const QDBusConnectionPrivate *s); - - mutable QMutex mutex; -private: - QHash<QString, QDBusConnectionPrivate *> connectionHash; - - mutable QMutex senderMutex; - QString senderName; // internal; will probably change -}; - Q_GLOBAL_STATIC(QDBusConnectionManager, _q_manager) QDBusConnectionPrivate *QDBusConnectionManager::sender() const @@ -126,6 +106,11 @@ QDBusConnectionManager::~QDBusConnectionManager() connectionHash.clear(); } +QDBusConnectionManager* QDBusConnectionManager::instance() +{ + return _q_manager(); +} + Q_DBUS_EXPORT void qDBusBindToApplication(); void qDBusBindToApplication() { @@ -371,7 +356,7 @@ QDBusConnection QDBusConnection::connectToBus(BusType type, const QString &name) } /*! - Opens a peer-to-peer connection on address \a address and associate with it the + Opens a connection to a private bus on address \a address and associate with it the connection name \a name. Returns a QDBusConnection object associated with that connection. */ QDBusConnection QDBusConnection::connectToBus(const QString &address, @@ -379,7 +364,7 @@ QDBusConnection QDBusConnection::connectToBus(const QString &address, { // Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection", // "Cannot create connection without a Q[Core]Application instance"); - if (!qdbus_loadLibDBus()){ + if (!qdbus_loadLibDBus()) { QDBusConnectionPrivate *d = 0; return QDBusConnection(d); } @@ -411,9 +396,43 @@ QDBusConnection QDBusConnection::connectToBus(const QString &address, return retval; } +/*! + \since 4.8 + + Opens a peer-to-peer connection on address \a address and associate with it the + connection name \a name. Returns a QDBusConnection object associated with that connection. +*/ +QDBusConnection QDBusConnection::connectToPeer(const QString &address, + const QString &name) +{ +// Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection", +// "Cannot create connection without a Q[Core]Application instance"); + if (!qdbus_loadLibDBus()) { + QDBusConnectionPrivate *d = 0; + return QDBusConnection(d); + } + + QMutexLocker locker(&_q_manager()->mutex); + + QDBusConnectionPrivate *d = _q_manager()->connection(name); + if (d || name.isEmpty()) + return QDBusConnection(d); + + d = new QDBusConnectionPrivate; + // setPeer does the error handling for us + QDBusErrorInternal error; + DBusConnection *c = q_dbus_connection_open_private(address.toUtf8().constData(), error); + + d->setPeer(c, error); + _q_manager()->setConnection(name, d); + + QDBusConnection retval(d); + + return retval; +} /*! - Closes the connection of name \a name. + Closes the bus connection of name \a name. Note that if there are still QDBusConnection objects associated with the same connection, the connection will not be closed until @@ -424,6 +443,30 @@ void QDBusConnection::disconnectFromBus(const QString &name) { if (_q_manager()) { QMutexLocker locker(&_q_manager()->mutex); + QDBusConnectionPrivate *d = _q_manager()->connection(name); + if (d && d->mode != QDBusConnectionPrivate::ClientMode) + return; + _q_manager()->removeConnection(name); + } +} + +/*! + \since 4.8 + + Closes the peer connection of name \a name. + + Note that if there are still QDBusConnection objects associated + with the same connection, the connection will not be closed until + all references are dropped. However, no further references can be + created using the QDBusConnection constructor. +*/ +void QDBusConnection::disconnectFromPeer(const QString &name) +{ + if (_q_manager()) { + QMutexLocker locker(&_q_manager()->mutex); + QDBusConnectionPrivate *d = _q_manager()->connection(name); + if (d && d->mode != QDBusConnectionPrivate::PeerMode) + return; _q_manager()->removeConnection(name); } } @@ -814,7 +857,7 @@ void QDBusConnection::unregisterObject(const QString &path, UnregisterMode mode) // find the object while (node) { - if (pathComponents.count() == i) { + if (pathComponents.count() == i || !path.compare(QLatin1String("/"))) { // found it node->obj = 0; node->flags = 0; diff --git a/src/dbus/qdbusconnection.h b/src/dbus/qdbusconnection.h index 6ab0ea2..15e08a7 100644 --- a/src/dbus/qdbusconnection.h +++ b/src/dbus/qdbusconnection.h @@ -172,7 +172,9 @@ public: static QDBusConnection connectToBus(BusType type, const QString &name); static QDBusConnection connectToBus(const QString &address, const QString &name); + static QDBusConnection connectToPeer(const QString &address, const QString &name); static void disconnectFromBus(const QString &name); + static void disconnectFromPeer(const QString &name); static QDBusConnection sessionBus(); static QDBusConnection systemBus(); diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h index 36f7c53..355a6e6 100644 --- a/src/dbus/qdbusconnection_p.h +++ b/src/dbus/qdbusconnection_p.h @@ -216,7 +216,7 @@ public: inline void serverConnection(const QDBusConnection &connection) { emit newServerConnection(connection); } - + private: void checkThread(); bool handleError(const QDBusErrorInternal &error); diff --git a/src/dbus/qdbusconnectionmanager_p.h b/src/dbus/qdbusconnectionmanager_p.h new file mode 100644 index 0000000..dd8b4aa --- /dev/null +++ b/src/dbus/qdbusconnectionmanager_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDBus module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the public API. This header file may +// change from version to version without notice, or even be +// removed. +// +// We mean it. +// +// + +#ifndef QDBUSCONNECTIONMANAGER_P_H +#define QDBUSCONNECTIONMANAGER_P_H + +#include "qdbusconnection_p.h" + +#ifndef QT_NO_DBUS + +QT_BEGIN_NAMESPACE + +class QDBusConnectionManager +{ +public: + QDBusConnectionManager() {} + ~QDBusConnectionManager(); + static QDBusConnectionManager* instance(); + + QDBusConnectionPrivate *connection(const QString &name) const; + void removeConnection(const QString &name); + void setConnection(const QString &name, QDBusConnectionPrivate *c); + + QDBusConnectionPrivate *sender() const; + void setSender(const QDBusConnectionPrivate *s); + + mutable QMutex mutex; +private: + QHash<QString, QDBusConnectionPrivate *> connectionHash; + + mutable QMutex senderMutex; + QString senderName; // internal; will probably change +}; + +QT_END_NAMESPACE + +#endif // QT_NO_DBUS +#endif diff --git a/src/dbus/qdbusdemarshaller.cpp b/src/dbus/qdbusdemarshaller.cpp index 111122e..3910381 100644 --- a/src/dbus/qdbusdemarshaller.cpp +++ b/src/dbus/qdbusdemarshaller.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qdbusargument_p.h" +#include "qdbusconnection.h" #include <stdlib.h> QT_BEGIN_NAMESPACE @@ -126,6 +127,13 @@ inline QDBusSignature QDBusDemarshaller::toSignature() return QDBusSignature(QString::fromUtf8(qIterGet<char *>(&iterator))); } +inline QDBusUnixFileDescriptor QDBusDemarshaller::toUnixFileDescriptor() +{ + QDBusUnixFileDescriptor fd; + fd.giveFileDescriptor(qIterGet<dbus_int32_t>(&iterator)); + return fd; +} + inline QDBusVariant QDBusDemarshaller::toVariant() { QDBusDemarshaller sub(capabilities); @@ -173,6 +181,10 @@ QDBusArgument::ElementType QDBusDemarshaller::currentType() case DBUS_TYPE_DICT_ENTRY: return QDBusArgument::MapEntryType; + case DBUS_TYPE_UNIX_FD: + return capabilities & QDBusConnection::UnixFileDescriptorPassing ? + QDBusArgument::BasicType : QDBusArgument::UnknownType; + case DBUS_TYPE_INVALID: return QDBusArgument::UnknownType; @@ -231,6 +243,11 @@ QVariant QDBusDemarshaller::toVariantInternal() case DBUS_TYPE_STRUCT: return QVariant::fromValue(duplicate()); + case DBUS_TYPE_UNIX_FD: + if (capabilities & QDBusConnection::UnixFileDescriptorPassing) + return qVariantFromValue(toUnixFileDescriptor()); + // fall through + default: // qWarning("QDBusDemarshaller: Found unknown D-Bus type %d '%c'", // q_dbus_message_iter_get_arg_type(&iterator), diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index ee917a5..b2095c7 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -377,28 +377,23 @@ static void qDBusUpdateDispatchStatus(DBusConnection *connection, DBusDispatchSt static void qDBusNewConnection(DBusServer *server, DBusConnection *connection, void *data) { - // ### We may want to separate the server from the QDBusConnectionPrivate + // ### We may want to separate the server from the QDBusConnectionPrivate Q_ASSERT(server); Q_UNUSED(server); Q_ASSERT(connection); Q_ASSERT(data); // keep the connection alive q_dbus_connection_ref(connection); - QDBusConnectionPrivate *d = new QDBusConnectionPrivate; - - // setConnection does the error handling for us + QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data); + + // setPeer does the error handling for us QDBusErrorInternal error; d->setPeer(connection, error); QDBusConnection retval = QDBusConnectionPrivate::q(d); - d->setBusService(retval); - - //d->name = QString::number(reinterpret_cast<int>(d)); - //d->setConnection(d->name, d); // make QDBusServer emit the newConnection signal - QDBusConnectionPrivate *server_d = static_cast<QDBusConnectionPrivate *>(data); - server_d->serverConnection(retval); + d->serverConnection(retval); } } // extern "C" @@ -435,6 +430,11 @@ static bool findObject(const QDBusConnectionPrivate::ObjectTreeNode *root, const QString &fullpath, int &usedLength, QDBusConnectionPrivate::ObjectTreeNode &result) { + if (!fullpath.compare(QLatin1String("/")) && root->obj) { + usedLength = 1; + result = *root; + return root; + } int start = 0; int length = fullpath.length(); if (fullpath.at(0) == QLatin1Char('/')) @@ -1036,11 +1036,10 @@ void QDBusConnectionPrivate::closeConnection() mode = InvalidMode; // prevent reentrancy baseService.clear(); - if (oldMode == ServerMode) { - if (server) { - q_dbus_server_disconnect(server); - } - } else if (oldMode == ClientMode || oldMode == PeerMode) { + if (server) + q_dbus_server_disconnect(server); + + if (oldMode == ClientMode || oldMode == PeerMode) { if (connection) { q_dbus_connection_close(connection); // send the "close" message @@ -1515,7 +1514,7 @@ QDBusActivateObjectEvent::~QDBusActivateObjectEvent() // semaphore releasing happens in ~QMetaCallEvent } -int QDBusActivateObjectEvent::placeMetaCall(QObject *) +void QDBusActivateObjectEvent::placeMetaCall(QObject *) { QDBusConnectionPrivate *that = QDBusConnectionPrivate::d(connection); @@ -1526,7 +1525,6 @@ int QDBusActivateObjectEvent::placeMetaCall(QObject *) QDBusLockerBase::AfterDeliver, that); handled = true; - return -1; } void QDBusConnectionPrivate::handleSignal(const QString &key, const QDBusMessage& msg) @@ -1630,7 +1628,7 @@ void QDBusConnectionPrivate::setServer(DBusServer *s, const QDBusErrorInternal & this, 0); //qDebug() << "time_functions_set" << time_functions_set; Q_UNUSED(time_functions_set); - + q_dbus_server_set_new_connection_function(server, qDBusNewConnection, this, 0); dbus_bool_t data_set = q_dbus_server_set_data(server, server_slot, this, 0); @@ -1647,7 +1645,7 @@ void QDBusConnectionPrivate::setPeer(DBusConnection *c, const QDBusErrorInternal connection = c; mode = PeerMode; - + q_dbus_connection_set_exit_on_disconnect(connection, false); q_dbus_connection_set_watch_functions(connection, qDBusAddWatch, @@ -1667,6 +1665,31 @@ void QDBusConnectionPrivate::setPeer(DBusConnection *c, const QDBusErrorInternal QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection); } +static QDBusConnection::ConnectionCapabilities connectionCapabilies(DBusConnection *connection) +{ + QDBusConnection::ConnectionCapabilities result = 0; + +#if defined(QT_LINKED_LIBDBUS) && DBUS_VERSION < 0x010400 + // no capabilities are possible +#else +# if !defined(QT_LINKED_LIBDBUS) + // run-time check if the next functions are available + int major, minor, micro; + q_dbus_get_version(&major, &minor, µ); + if (major == 1 && minor < 4) + return result; +# endif + +#ifndef DBUS_TYPE_UNIX_FD +# define DBUS_TYPE_UNIX_FD int('h') +#endif + if (q_dbus_connection_can_send_type(connection, DBUS_TYPE_UNIX_FD)) + result |= QDBusConnection::UnixFileDescriptorPassing; +#endif + + return result; +} + void QDBusConnectionPrivate::setConnection(DBusConnection *dbc, const QDBusErrorInternal &error) { if (!dbc) { @@ -1680,6 +1703,7 @@ void QDBusConnectionPrivate::setConnection(DBusConnection *dbc, const QDBusError const char *service = q_dbus_bus_get_unique_name(connection); Q_ASSERT(service); baseService = QString::fromUtf8(service); + capabilities = connectionCapabilies(connection); q_dbus_connection_set_exit_on_disconnect(connection, false); q_dbus_connection_set_watch_functions(connection, qDBusAddWatch, qDBusRemoveWatch, @@ -2073,21 +2097,23 @@ void QDBusConnectionPrivate::connectSignal(const QString &key, const SignalHook matchRefCounts.insert(hook.matchRule, 1); if (connection) { - qDBusDebug("Adding rule: %s", hook.matchRule.constData()); - q_dbus_bus_add_match(connection, hook.matchRule, NULL); - - // Successfully connected the signal - // Do we need to watch for this name? - if (shouldWatchService(hook.service)) { - WatchedServicesHash::mapped_type &data = watchedServices[hook.service]; - if (++data.refcount == 1) { - // we need to watch for this service changing - connectSignal(dbusServiceString(), QString(), dbusInterfaceString(), - QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(), - this, SLOT(serviceOwnerChangedNoLock(QString,QString,QString))); - data.owner = getNameOwnerNoCache(hook.service); - qDBusDebug() << this << "Watching service" << hook.service << "for owner changes (current owner:" - << data.owner << ")"; + if (mode != QDBusConnectionPrivate::PeerMode) { + qDBusDebug("Adding rule: %s", hook.matchRule.constData()); + q_dbus_bus_add_match(connection, hook.matchRule, NULL); + + // Successfully connected the signal + // Do we need to watch for this name? + if (shouldWatchService(hook.service)) { + WatchedServicesHash::mapped_type &data = watchedServices[hook.service]; + if (++data.refcount == 1) { + // we need to watch for this service changing + connectSignal(dbusServiceString(), QString(), dbusInterfaceString(), + QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(), + this, SLOT(serviceOwnerChangedNoLock(QString,QString,QString))); + data.owner = getNameOwnerNoCache(hook.service); + qDBusDebug() << this << "Watching service" << hook.service << "for owner changes (current owner:" + << data.owner << ")"; + } } } } @@ -2151,18 +2177,20 @@ QDBusConnectionPrivate::disconnectSignal(SignalHookHash::Iterator &it) // we don't care about errors here if (connection && erase) { - qDBusDebug("Removing rule: %s", hook.matchRule.constData()); - q_dbus_bus_remove_match(connection, hook.matchRule, NULL); - - // Successfully disconnected the signal - // Were we watching for this name? - WatchedServicesHash::Iterator sit = watchedServices.find(hook.service); - if (sit != watchedServices.end()) { - if (--sit.value().refcount == 0) { - watchedServices.erase(sit); - disconnectSignal(dbusServiceString(), QString(), dbusInterfaceString(), - QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(), - this, SLOT(_q_serviceOwnerChanged(QString,QString,QString))); + if (mode != QDBusConnectionPrivate::PeerMode) { + qDBusDebug("Removing rule: %s", hook.matchRule.constData()); + q_dbus_bus_remove_match(connection, hook.matchRule, NULL); + + // Successfully disconnected the signal + // Were we watching for this name? + WatchedServicesHash::Iterator sit = watchedServices.find(hook.service); + if (sit != watchedServices.end()) { + if (--sit.value().refcount == 0) { + watchedServices.erase(sit); + disconnectSignal(dbusServiceString(), QString(), dbusInterfaceString(), + QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(), + this, SLOT(_q_serviceOwnerChanged(QString,QString,QString))); + } } } @@ -2365,7 +2393,7 @@ void QDBusConnectionPrivate::unregisterServiceNoLock(const QString &serviceName) bool QDBusConnectionPrivate::isServiceRegisteredByThread(const QString &serviceName) const { - if (serviceName == baseService) + if (!serviceName.isEmpty() && serviceName == baseService) return true; QStringList copy = serviceNames; return copy.contains(serviceName); diff --git a/src/dbus/qdbusintegrator_p.h b/src/dbus/qdbusintegrator_p.h index 4047c24..59255f9 100644 --- a/src/dbus/qdbusintegrator_p.h +++ b/src/dbus/qdbusintegrator_p.h @@ -95,13 +95,12 @@ class QDBusCallDeliveryEvent: public QMetaCallEvent public: QDBusCallDeliveryEvent(const QDBusConnection &c, int id, QObject *sender, const QDBusMessage &msg, const QList<int> &types, int f = 0) - : QMetaCallEvent(id, sender, -1), connection(c), message(msg), metaTypes(types), flags(f) + : QMetaCallEvent(0, id, 0, sender, -1), connection(c), message(msg), metaTypes(types), flags(f) { } - int placeMetaCall(QObject *object) + void placeMetaCall(QObject *object) { QDBusConnectionPrivate::d(connection)->deliverCall(object, flags, message, metaTypes, id()); - return -1; } private: @@ -117,12 +116,12 @@ public: QDBusActivateObjectEvent(const QDBusConnection &c, QObject *sender, const QDBusConnectionPrivate::ObjectTreeNode &n, int p, const QDBusMessage &m, QSemaphore *s = 0) - : QMetaCallEvent(-1, sender, -1, 0, 0, 0, s), connection(c), node(n), + : QMetaCallEvent(0, -1, 0, sender, -1, 0, 0, 0, s), connection(c), node(n), pathStartPos(p), message(m), handled(false) { } ~QDBusActivateObjectEvent(); - int placeMetaCall(QObject *); + void placeMetaCall(QObject *); private: QDBusConnection connection; // just for refcounting diff --git a/src/dbus/qdbusmarshaller.cpp b/src/dbus/qdbusmarshaller.cpp index 76d76cc..6dec359 100644 --- a/src/dbus/qdbusmarshaller.cpp +++ b/src/dbus/qdbusmarshaller.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qdbusargument_p.h" +#include "qdbusconnection.h" #include "qdbusmetatype_p.h" #include "qdbusutil_p.h" @@ -138,6 +139,16 @@ inline void QDBusMarshaller::append(const QDBusSignature &arg) qIterAppend(&iterator, ba, DBUS_TYPE_SIGNATURE, &cdata); } +inline void QDBusMarshaller::append(const QDBusUnixFileDescriptor &arg) +{ + int fd = arg.fileDescriptor(); + if (!ba && fd == -1) { + error(QLatin1String("Invalid file descriptor passed in arguments")); + } else { + qIterAppend(&iterator, ba, DBUS_TYPE_UNIX_FD, &fd); + } +} + inline void QDBusMarshaller::append(const QByteArray &arg) { if (ba) { @@ -243,7 +254,7 @@ inline QDBusMarshaller *QDBusMarshaller::beginMap(int kid, int vid) .arg(QLatin1String(QVariant::typeToName(QVariant::Type(kid))))); return this; } - if (ksignature[1] != 0 || !q_dbus_type_is_basic(*ksignature)) { + if (ksignature[1] != 0 || !QDBusUtil::isValidBasicType(*ksignature)) { qWarning("QDBusMarshaller: type '%s' (%d) cannot be used as the key type in a D-BUS map.", QVariant::typeToName( QVariant::Type(kid) ), kid); error(QString::fromLatin1("Type %1 passed in arguments cannot be used as a key in a map") @@ -474,6 +485,13 @@ bool QDBusMarshaller::appendVariantInternal(const QVariant &arg) qFatal("QDBusMarshaller::appendVariantInternal got a DICT_ENTRY!"); return false; + case DBUS_TYPE_UNIX_FD: + if (capabilities & QDBusConnection::UnixFileDescriptorPassing || ba) { + append(qvariant_cast<QDBusUnixFileDescriptor>(arg)); + return true; + } + // fall through + default: qWarning("QDBusMarshaller::appendVariantInternal: Found unknown D-BUS type '%s'", signature); @@ -493,7 +511,7 @@ bool QDBusMarshaller::appendRegisteredType(const QVariant &arg) bool QDBusMarshaller::appendCrossMarshalling(QDBusDemarshaller *demarshaller) { int code = q_dbus_message_iter_get_arg_type(&demarshaller->iterator); - if (q_dbus_type_is_basic(code)) { + if (QDBusUtil::isValidBasicType(code)) { // easy: just append // do exactly like the D-BUS docs suggest // (see apidocs for q_dbus_message_iter_get_basic) @@ -507,7 +525,7 @@ bool QDBusMarshaller::appendCrossMarshalling(QDBusDemarshaller *demarshaller) if (code == DBUS_TYPE_ARRAY) { int element = q_dbus_message_iter_get_element_type(&demarshaller->iterator); - if (q_dbus_type_is_fixed(element)) { + if (QDBusUtil::isValidFixedType(element) && element != DBUS_TYPE_UNIX_FD) { // another optimization: fixed size arrays // code is exactly like QDBusDemarshaller::toByteArray DBusMessageIter sub; diff --git a/src/dbus/qdbusmetatype.cpp b/src/dbus/qdbusmetatype.cpp index 9f29205..9d9112c 100644 --- a/src/dbus/qdbusmetatype.cpp +++ b/src/dbus/qdbusmetatype.cpp @@ -50,12 +50,18 @@ #include <qvector.h> #include "qdbusmessage.h" +#include "qdbusunixfiledescriptor.h" #include "qdbusutil_p.h" #include "qdbusmetatype_p.h" #include "qdbusargument_p.h" #ifndef QT_NO_DBUS +#ifndef DBUS_TYPE_UNIX_FD +# define DBUS_TYPE_UNIX_FD int('h') +# define DBUS_TYPE_UNIX_FD_AS_STRING "h" +#endif + Q_DECLARE_METATYPE(QList<bool>) Q_DECLARE_METATYPE(QList<short>) Q_DECLARE_METATYPE(QList<ushort>) @@ -96,6 +102,7 @@ int QDBusMetaTypeId::variant; int QDBusMetaTypeId::objectpath; int QDBusMetaTypeId::signature; int QDBusMetaTypeId::error; +int QDBusMetaTypeId::unixfd; void QDBusMetaTypeId::init() { @@ -110,7 +117,8 @@ void QDBusMetaTypeId::init() variant = qRegisterMetaType<QDBusVariant>("QDBusVariant"); objectpath = qRegisterMetaType<QDBusObjectPath>("QDBusObjectPath"); signature = qRegisterMetaType<QDBusSignature>("QDBusSignature"); - error = qRegisterMetaType<QDBusError>("QDBusError"); + error = qRegisterMetaType<QDBusError>("QDBusError"); + unixfd = qRegisterMetaType<QDBusUnixFileDescriptor>("QDBusUnixFileDescriptor"); #ifndef QDBUS_NO_SPECIALTYPES // and register QtCore's with us @@ -139,6 +147,7 @@ void QDBusMetaTypeId::init() qDBusRegisterMetaType<QList<double> >(); qDBusRegisterMetaType<QList<QDBusObjectPath> >(); qDBusRegisterMetaType<QList<QDBusSignature> >(); + qDBusRegisterMetaType<QList<QDBusUnixFileDescriptor> >(); #endif initialized = true; @@ -343,6 +352,9 @@ int QDBusMetaType::signatureToType(const char *signature) case DBUS_TYPE_SIGNATURE: return QDBusMetaTypeId::signature; + case DBUS_TYPE_UNIX_FD: + return QDBusMetaTypeId::unixfd; + case DBUS_TYPE_VARIANT: return QDBusMetaTypeId::variant; @@ -432,6 +444,8 @@ const char *QDBusMetaType::typeToSignature(int type) return DBUS_TYPE_OBJECT_PATH_AS_STRING; else if (type == QDBusMetaTypeId::signature) return DBUS_TYPE_SIGNATURE_AS_STRING; + else if (type == QDBusMetaTypeId::unixfd) + return DBUS_TYPE_UNIX_FD_AS_STRING; // try the database QVector<QDBusCustomTypeInfo> *ct = customTypes(); diff --git a/src/dbus/qdbusmetatype_p.h b/src/dbus/qdbusmetatype_p.h index 2fce133..b931c75 100644 --- a/src/dbus/qdbusmetatype_p.h +++ b/src/dbus/qdbusmetatype_p.h @@ -65,6 +65,7 @@ struct QDBusMetaTypeId static int objectpath; // QDBusObjectPath static int signature; // QDBusSignature static int error; // QDBusError + static int unixfd; // QDBusUnixFileDescriptor static void init(); }; diff --git a/src/dbus/qdbusserver.cpp b/src/dbus/qdbusserver.cpp index 9b61555..abc5cb3 100644 --- a/src/dbus/qdbusserver.cpp +++ b/src/dbus/qdbusserver.cpp @@ -41,6 +41,7 @@ #include "qdbusserver.h" #include "qdbusconnection_p.h" +#include "qdbusconnectionmanager_p.h" #ifndef QT_NO_DBUS @@ -62,24 +63,37 @@ QT_BEGIN_NAMESPACE QDBusServer::QDBusServer(const QString &address, QObject *parent) : QObject(parent) { + if (address.isEmpty()) + return; + if (!qdbus_loadLibDBus()) { d = 0; return; } d = new QDBusConnectionPrivate(this); - if (address.isEmpty()) - return; + QMutexLocker locker(&QDBusConnectionManager::instance()->mutex); + QDBusConnectionManager::instance()->setConnection(QLatin1String("QDBusServer-") + QString::number(reinterpret_cast<qulonglong>(d)), d); QObject::connect(d, SIGNAL(newServerConnection(QDBusConnection)), this, SIGNAL(newConnection(QDBusConnection))); - // server = q_dbus_server_listen( "unix:tmpdir=/tmp", &error); QDBusErrorInternal error; d->setServer(q_dbus_server_listen(address.toUtf8().constData(), error), error); } /*! + Destructs a QDBusServer +*/ +QDBusServer::~QDBusServer() +{ + if (QDBusConnectionManager::instance()) { + QMutexLocker locker(&QDBusConnectionManager::instance()->mutex); + QDBusConnectionManager::instance()->removeConnection(d->name); + } +} + +/*! Returns true if this QDBusServer object is connected. If it isn't connected, you need to call the constructor again. @@ -113,11 +127,12 @@ QString QDBusServer::address() const return addr; } + /*! \fn void QDBusServer::newConnection(const QDBusConnection &connection) - This signal is currently not used, but if and when it is - used, \a connection will be the new connection. + This signal is emitted when a new client connection \a connection is + established to the server. */ QT_END_NAMESPACE diff --git a/src/dbus/qdbusserver.h b/src/dbus/qdbusserver.h index f101011..fcb78bd 100644 --- a/src/dbus/qdbusserver.h +++ b/src/dbus/qdbusserver.h @@ -61,7 +61,8 @@ class Q_DBUS_EXPORT QDBusServer: public QObject { Q_OBJECT public: - QDBusServer(const QString &address, QObject *parent = 0); + QDBusServer(const QString &address = "unix:tmpdir=/tmp", QObject *parent = 0); + virtual ~QDBusServer(); bool isConnected() const; QDBusError lastError() const; diff --git a/src/dbus/qdbusunixfiledescriptor.cpp b/src/dbus/qdbusunixfiledescriptor.cpp new file mode 100644 index 0000000..f45b6cc --- /dev/null +++ b/src/dbus/qdbusunixfiledescriptor.cpp @@ -0,0 +1,316 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qdbusunixfiledescriptor.h" +#include <QSharedData> + +#ifdef Q_OS_UNIX +# include <private/qcore_unix_p.h> +#endif + +QT_BEGIN_NAMESPACE + +/*! + \class QDBusUnixFileDescriptor + \inmodule QtDBus + \since 4.8 + + \brief The QDBusUnixFileDescriptor class holds one Unix file descriptor. + + The QDBusUnixFileDescriptor class is used to hold one Unix file + descriptor for use with the QtDBus module. This allows applications to + send and receive Unix file descriptors over the D-Bus connection, mapping + automatically to the D-Bus type 'h'. + + Objects of type QDBusUnixFileDescriptors can be used also as parameters + in signals and slots that get exported to D-Bus by registering with + QDBusConnection::registerObject. + + QDBusUnixFileDescriptor does not take ownership of the file descriptor. + Instead, it will use the Unix system call \c dup(2) to make a copy of the + file descriptor. This file descriptor belongs to the + QDBusUnixFileDescriptor object and should not be stored or closed by the + user. Instead, you should make your own copy if you need that. + + \section2 Availability + + Unix file descriptor passing is not available in all D-Bus connections. + This feature is present with D-Bus library and bus daemon version 1.4 and + upwards on Unix systems. QtDBus automatically enables the feature if such + a version was found at compile-time and run-time. + + To verify that your connection does support passing file descriptors, + check if the QDBusConnection::UnixFileDescriptorPassing capability is set + with QDBusConnection::connectionCapabilities(). If the flag is not + active, then you will not be able to make calls to methods that have + QDBusUnixFileDescriptor as arguments or even embed such a type in a + variant. You will also not receive calls containing that type. + + Note also that remote applications may not have support for Unix file + descriptor passing. If you make a D-Bus to a remote application that + cannot receive such a type, you will receive an error reply. If you try + to send a signal containing a D-Bus file descriptor or return one from a + method call, the message will be silently dropped. + + Even if the feature is not available, QDBusUnixFileDescriptor will + continue to operate, so code need not have compile-time checks for the + availability of this feature. + + On non-Unix systems, QDBusUnixFileDescriptor will always report an + invalid state and QDBusUnixFileDescriptor::isSupported() will return + false. + + \sa QDBusConnection::ConnectionCapabilities, QDBusConnection::connectionCapabilities +*/ + +class QDBusUnixFileDescriptorPrivate : public QSharedData { +public: + QDBusUnixFileDescriptorPrivate() : fd(-1) { } + QDBusUnixFileDescriptorPrivate(const QDBusUnixFileDescriptorPrivate &other) + : QSharedData(other), fd(-1) + { } + ~QDBusUnixFileDescriptorPrivate(); + + QAtomicInt fd; +}; + +template<> inline +QExplicitlySharedDataPointer<QDBusUnixFileDescriptorPrivate>::~QExplicitlySharedDataPointer() +{ if (d && !d->ref.deref()) delete d; } + +/*! + Constructs a QDBusUnixFileDescriptor without a wrapped file descriptor. + This is equivalent to constructing the object with an invalid file + descriptor (like -1). + + \sa fileDescriptor, isValid +*/ +QDBusUnixFileDescriptor::QDBusUnixFileDescriptor() + : d(0) +{ +} + +/*! + Constructs a QDBusUnixFileDescriptor object by copying the \a + fileDescriptor parameter. The original file descriptor is not touched and + must be closed by the user. + + Note that the value returned by fileDescriptor() will be different from + the \a fileDescriptor parameter passed. + + If the \a fileDescriptor parameter is not valid, isValid() will return + false and fileDescriptor() will return -1. + + \sa setFileDescriptor, fileDescriptor +*/ +QDBusUnixFileDescriptor::QDBusUnixFileDescriptor(int fileDescriptor) + : d(0) +{ + if (fileDescriptor != -1) + setFileDescriptor(fileDescriptor); +} + +/*! + Constructs a QDBusUnixFileDescriptor object by copying \a other. +*/ +QDBusUnixFileDescriptor::QDBusUnixFileDescriptor(const QDBusUnixFileDescriptor &other) + : d(other.d) +{ +} + +/*! + Copies the Unix file descriptor from the \a other QDBusUnixFileDescriptor + object. If the current object contained a file descriptor, it will be + properly disposed of before. +*/ +QDBusUnixFileDescriptor &QDBusUnixFileDescriptor::operator=(const QDBusUnixFileDescriptor &other) +{ + if (this != &other) + d.operator=(other.d); + return *this; +} + +/*! + Destroys this QDBusUnixFileDescriptor object and disposes of the Unix file descriptor that it contained. +*/ +QDBusUnixFileDescriptor::~QDBusUnixFileDescriptor() +{ +} + +/*! + Returns true if this Unix file descriptor is valid. A valid Unix file + descriptor is not -1. + + \sa fileDescriptor() +*/ +bool QDBusUnixFileDescriptor::isValid() const +{ + return d ? d->fd != -1 : false; +} + +/*! + Returns the Unix file descriptor contained by this + QDBusUnixFileDescriptor object. An invalid file descriptor is represented + by the value -1. + + Note that the file descriptor returned by this function is owned by the + QDBusUnixFileDescriptor object and must not be stored past the lifetime + of this object. It is ok to use it while this object is valid, but if one + wants to store it for longer use, the file descriptor should be cloned + using the Unix \c dup(2), \c dup2(2) or \c dup3(2) functions. + + \sa isValid() +*/ +int QDBusUnixFileDescriptor::fileDescriptor() const +{ + return d ? d->fd.operator int() : -1; +} + +// actual implementation +#ifdef Q_OS_UNIX + +// qdoc documentation is generated on Unix + +/*! + Returns true if Unix file descriptors are supported on this platform. In + other words, this function returns true if this is a Unix platform. + + Note that QDBusUnixFileDescriptor continues to operate even if this + function returns false. The only difference is that the + QDBusUnixFileDescriptor objects will always be in the isValid() == false + state and fileDescriptor() will always return -1. The class will not + consume any operating system resources. +*/ +bool QDBusUnixFileDescriptor::isSupported() +{ + return true; +} + +/*! + Sets the file descriptor that this QDBusUnixFileDescriptor object holds + to a copy of \a fileDescriptor.T he original file descriptor is not + touched and must be closed by the user. + + Note that the value returned by fileDescriptor() will be different from + the \a fileDescriptor parameter passed. + + If the \a fileDescriptor parameter is not valid, isValid() will return + false and fileDescriptor() will return -1. + + \sa isValid(), fileDescriptor() +*/ +void QDBusUnixFileDescriptor::setFileDescriptor(int fileDescriptor) +{ + if (fileDescriptor != -1) + giveFileDescriptor(qt_safe_dup(fileDescriptor)); +} + +/*! + \internal + Sets the Unix file descriptor to \a fileDescriptor without copying. + + \sa setFileDescriptor() +*/ +void QDBusUnixFileDescriptor::giveFileDescriptor(int fileDescriptor) +{ + // if we are the sole ref, d remains unchanged + // if detaching happens, d->fd will be -1 + if (d) + d.detach(); + else + d = new QDBusUnixFileDescriptorPrivate; + + if (d->fd != -1) + qt_safe_close(d->fd); + + if (fileDescriptor != -1) + d->fd = fileDescriptor; +} + +/*! + \internal + Extracts the Unix file descriptor from the QDBusUnixFileDescriptor object + and transfers ownership. + + Note: since QDBusUnixFileDescriptor is implicitly shared, this function + is inherently racy and should be avoided. +*/ +int QDBusUnixFileDescriptor::takeFileDescriptor() +{ + if (!d) + return -1; + + return d->fd.fetchAndStoreRelaxed(-1); +} + +QDBusUnixFileDescriptorPrivate::~QDBusUnixFileDescriptorPrivate() +{ + if (fd != -1) + qt_safe_close(fd); +} + +#else +bool QDBusUnixFileDescriptor::isSupported() +{ + return false; +} + +void QDBusUnixFileDescriptor::setFileDescriptor(int) +{ +} + +void QDBusUnixFileDescriptor::giveFileDescriptor(int) +{ +} + +int QDBusUnixFileDescriptor::takeFileDescriptor() +{ + return -1; +} + +QDBusUnixFileDescriptorPrivate::~QDBusUnixFileDescriptorPrivate() +{ +} + +#endif + +QT_END_NAMESPACE diff --git a/src/dbus/qdbusunixfiledescriptor.h b/src/dbus/qdbusunixfiledescriptor.h new file mode 100644 index 0000000..d0a2f3c --- /dev/null +++ b/src/dbus/qdbusunixfiledescriptor.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QDBUSUNIXFILEDESCRIPTOR_H +#define QDBUSUNIXFILEDESCRIPTOR_H + +#include <QtCore/QSharedDataPointer> +#include <QtDBus/qdbusmacros.h> + +#ifndef QT_NO_DBUS + +#ifdef Q_COMPILER_RVALUE_REFS +# include <utility> +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(DBus) + +class QDBusUnixFileDescriptorPrivate; +template<> QExplicitlySharedDataPointer<QDBusUnixFileDescriptorPrivate>::~QExplicitlySharedDataPointer(); + +class Q_DBUS_EXPORT QDBusUnixFileDescriptor +{ +public: + QDBusUnixFileDescriptor(); + explicit QDBusUnixFileDescriptor(int fileDescriptor); + QDBusUnixFileDescriptor(const QDBusUnixFileDescriptor &other); + QDBusUnixFileDescriptor &operator=(const QDBusUnixFileDescriptor &other); + ~QDBusUnixFileDescriptor(); + + bool isValid() const; + + int fileDescriptor() const; + void setFileDescriptor(int fileDescriptor); + + void giveFileDescriptor(int fileDescriptor); + int takeFileDescriptor(); + + static bool isSupported(); + +#if defined(Q_COMPILER_RVALUE_REFS) + QDBusUnixFileDescriptor(QDBusUnixFileDescriptor &&other) : d(static_cast<Data &&>(other.d)) + { } + inline QDBusUnixFileDescriptor &operator=(QDBusUnixFileDescriptor &&other) + { d.swap(other.d); return *this; } +#endif + +protected: + typedef QExplicitlySharedDataPointer<QDBusUnixFileDescriptorPrivate> Data; + Data d; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QDBusUnixFileDescriptor) +Q_DECLARE_METATYPE(QList<QDBusUnixFileDescriptor>) + +QT_END_HEADER + +#endif // QT_NO_DBUS +#endif // QDBUSUNIXFILEDESCRIPTOR_H diff --git a/src/dbus/qdbusutil.cpp b/src/dbus/qdbusutil.cpp index 9730f54..a4bd168 100644 --- a/src/dbus/qdbusutil.cpp +++ b/src/dbus/qdbusutil.cpp @@ -46,6 +46,7 @@ #include <QtCore/qstringlist.h> #include "qdbusargument.h" +#include "qdbusunixfiledescriptor.h" #ifndef QT_NO_DBUS @@ -130,6 +131,10 @@ static bool variantToString(const QVariant &arg, QString &out) } else if (argType == qMetaTypeId<QDBusSignature>()) { out += QLatin1String("[Signature: ") + qvariant_cast<QDBusSignature>(arg).signature(); out += QLatin1Char(']'); + } else if (argType == qMetaTypeId<QDBusUnixFileDescriptor>()) { + out += QLatin1String("[Unix FD: "); + out += QLatin1String(qvariant_cast<QDBusUnixFileDescriptor>(arg).isValid() ? "valid" : "not valid"); + out += QLatin1Char(']'); } else if (argType == qMetaTypeId<QDBusVariant>()) { const QVariant v = qvariant_cast<QDBusVariant>(arg).variant(); out += QLatin1String("[Variant"); @@ -233,6 +238,68 @@ bool argToString(const QDBusArgument &busArg, QString &out) return true; } +//------- D-Bus Types -------- +static const char oneLetterTypes[] = "vsogybnqiuxtdh"; +static const char basicTypes[] = "sogybnqiuxtdh"; +static const char fixedTypes[] = "ybnqiuxtdh"; + +static bool isBasicType(int c) +{ + return c != DBUS_TYPE_INVALID && strchr(basicTypes, c) != NULL; +} + +static bool isFixedType(int c) +{ + return c != DBUS_TYPE_INVALID && strchr(fixedTypes, c) != NULL; +} + +// Returns a pointer to one-past-end of this type if it's valid; +// returns NULL if it isn't valid. +static const char *validateSingleType(const char *signature) +{ + register char c = *signature; + if (c == DBUS_TYPE_INVALID) + return false; + + // is it one of the one-letter types? + if (strchr(oneLetterTypes, c) != NULL) + return signature + 1; + + // is it an array? + if (c == DBUS_TYPE_ARRAY) { + // then it's valid if the next type is valid + // or if it's a dict-entry + c = *++signature; + if (c == DBUS_DICT_ENTRY_BEGIN_CHAR) { + // beginning of a dictionary entry + // a dictionary entry has a key which is of basic types + // and a free value + c = *++signature; + if (!isBasicType(c)) + return 0; + signature = validateSingleType(signature + 1); + return signature && *signature == DBUS_DICT_ENTRY_END_CHAR ? signature + 1 : 0; + } + + return validateSingleType(signature); + } + + if (c == DBUS_STRUCT_BEGIN_CHAR) { + // beginning of a struct + ++signature; + while (true) { + signature = validateSingleType(signature); + if (!signature) + return 0; + if (*signature == DBUS_STRUCT_END_CHAR) + return signature + 1; + } + } + + // invalid/unknown type + return 0; +} + /*! \namespace QDBusUtil \inmodule QtDBus @@ -442,6 +509,25 @@ namespace QDBusUtil } /*! + \fn bool QDBusUtil::isValidBasicType(int type) + Returns true if \a c is a valid, basic D-Bus type. + */ + bool isValidBasicType(int c) + { + return isBasicType(c); + } + + /*! + \fn bool QDBusUtil::isValidFixedType(int type) + Returns true if \a c is a valid, fixed D-Bus type. + */ + bool isValidFixedType(int c) + { + return isFixedType(c); + } + + + /*! \fn bool QDBusUtil::isValidSignature(const QString &signature) Returns true if \a signature is a valid D-Bus type signature for one or more types. This function returns true if it can all of \a signature into valid, individual types and no @@ -451,7 +537,15 @@ namespace QDBusUtil */ bool isValidSignature(const QString &signature) { - return q_dbus_signature_validate(signature.toUtf8(), 0); + QByteArray ba = signature.toLatin1(); + const char *data = ba.constData(); + while (true) { + data = validateSingleType(data); + if (!data) + return false; + if (*data == '\0') + return true; + } } /*! @@ -462,7 +556,9 @@ namespace QDBusUtil */ bool isValidSingleSignature(const QString &signature) { - return q_dbus_signature_validate_single(signature.toUtf8(), 0); + QByteArray ba = signature.toLatin1(); + const char *data = validateSingleType(ba.constData()); + return data && *data == '\0'; } } // namespace QDBusUtil diff --git a/src/dbus/qdbusutil_p.h b/src/dbus/qdbusutil_p.h index 3721e98..24b5cea 100644 --- a/src/dbus/qdbusutil_p.h +++ b/src/dbus/qdbusutil_p.h @@ -81,6 +81,10 @@ namespace QDBusUtil Q_DBUS_EXPORT bool isValidObjectPath(const QString &path); + Q_DBUS_EXPORT bool isValidFixedType(int c); + + Q_DBUS_EXPORT bool isValidBasicType(int c); + Q_DBUS_EXPORT bool isValidSignature(const QString &signature); Q_DBUS_EXPORT bool isValidSingleSignature(const QString &signature); |