00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <qcoreapplication.h>
00025 #include <qcoreevent.h>
00026 #include <qdebug.h>
00027 #include <qmetaobject.h>
00028 #include <qobject.h>
00029 #include <qsocketnotifier.h>
00030 #include <qstringlist.h>
00031 #include <qtimer.h>
00032
00033 #include "qdbusargument.h"
00034 #include "qdbusconnection_p.h"
00035 #include "qdbusinterface_p.h"
00036 #include "qdbusmessage.h"
00037 #include "qdbusmetatype.h"
00038 #include "qdbusmetatype_p.h"
00039 #include "qdbusabstractadaptor.h"
00040 #include "qdbusabstractadaptor_p.h"
00041 #include "qdbusutil_p.h"
00042 #include "qdbusmessage_p.h"
00043
00044 static bool isDebugging;
00045 #define qDBusDebug if (!::isDebugging); else qDebug
00046
00047 #ifndef USE_OUTSIDE_DISPATCH
00048 # define USE_OUTSIDE_DISPATCH 0
00049 #endif
00050
00051 typedef void (*QDBusSpyHook)(const QDBusMessage&);
00052 typedef QVarLengthArray<QDBusSpyHook, 4> QDBusSpyHookList;
00053 Q_GLOBAL_STATIC(QDBusSpyHookList, qDBusSpyHookList)
00054
00055 Q_GLOBAL_STATIC(QStringList, qDBusServicesRegisteredByThread)
00056
00057 struct QDBusPendingCall
00058 {
00059 QPointer<QObject> receiver;
00060 QList<int> metaTypes;
00061 int methodIdx;
00062 DBusPendingCall *pending;
00063 const QDBusConnectionPrivate *connection;
00064 };
00065
00066 class CallDeliveryEvent: public QEvent
00067 {
00068 public:
00069 CallDeliveryEvent()
00070 : QEvent(QEvent::User), object(0), flags(0), slotIdx(-1)
00071 { }
00072
00073 const QDBusConnectionPrivate *conn;
00074 QPointer<QObject> object;
00075 QDBusMessage message;
00076 QList<int> metaTypes;
00077
00078 int flags;
00079 int slotIdx;
00080 };
00081
00082 static dbus_bool_t qDBusAddTimeout(DBusTimeout *timeout, void *data)
00083 {
00084 Q_ASSERT(timeout);
00085 Q_ASSERT(data);
00086
00087
00088
00089 QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
00090
00091 if (!dbus_timeout_get_enabled(timeout))
00092 return true;
00093
00094 if (!QCoreApplication::instance()) {
00095 d->pendingTimeouts.append(timeout);
00096 return true;
00097 }
00098 int timerId = d->startTimer(dbus_timeout_get_interval(timeout));
00099 if (!timerId)
00100 return false;
00101
00102 d->timeouts[timerId] = timeout;
00103 return true;
00104 }
00105
00106 static void qDBusRemoveTimeout(DBusTimeout *timeout, void *data)
00107 {
00108 Q_ASSERT(timeout);
00109 Q_ASSERT(data);
00110
00111
00112
00113 QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
00114 d->pendingTimeouts.removeAll(timeout);
00115
00116 QDBusConnectionPrivate::TimeoutHash::iterator it = d->timeouts.begin();
00117 while (it != d->timeouts.end()) {
00118 if (it.value() == timeout) {
00119 d->killTimer(it.key());
00120 it = d->timeouts.erase(it);
00121 } else {
00122 ++it;
00123 }
00124 }
00125 }
00126
00127 static void qDBusToggleTimeout(DBusTimeout *timeout, void *data)
00128 {
00129 Q_ASSERT(timeout);
00130 Q_ASSERT(data);
00131
00132
00133
00134 qDBusRemoveTimeout(timeout, data);
00135 qDBusAddTimeout(timeout, data);
00136 }
00137
00138 static dbus_bool_t qDBusAddWatch(DBusWatch *watch, void *data)
00139 {
00140 Q_ASSERT(watch);
00141 Q_ASSERT(data);
00142
00143 QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
00144
00145 int flags = dbus_watch_get_flags(watch);
00146 int fd = dbus_watch_get_fd(watch);
00147
00148 QDBusConnectionPrivate::Watcher watcher;
00149 if (flags & DBUS_WATCH_READABLE) {
00150
00151 watcher.watch = watch;
00152 if (QCoreApplication::instance()) {
00153 watcher.read = new QSocketNotifier(fd, QSocketNotifier::Read, d);
00154 watcher.read->setEnabled(dbus_watch_get_enabled(watch));
00155 d->connect(watcher.read, SIGNAL(activated(int)), SLOT(socketRead(int)));
00156 }
00157 }
00158 if (flags & DBUS_WATCH_WRITABLE) {
00159
00160 watcher.watch = watch;
00161 if (QCoreApplication::instance()) {
00162 watcher.write = new QSocketNotifier(fd, QSocketNotifier::Write, d);
00163 watcher.write->setEnabled(dbus_watch_get_enabled(watch));
00164 d->connect(watcher.write, SIGNAL(activated(int)), SLOT(socketWrite(int)));
00165 }
00166 }
00167 d->watchers.insertMulti(fd, watcher);
00168
00169 return true;
00170 }
00171
00172 static void qDBusRemoveWatch(DBusWatch *watch, void *data)
00173 {
00174 Q_ASSERT(watch);
00175 Q_ASSERT(data);
00176
00177
00178
00179 QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
00180 int fd = dbus_watch_get_fd(watch);
00181
00182 QDBusConnectionPrivate::WatcherHash::iterator i = d->watchers.find(fd);
00183 while (i != d->watchers.end() && i.key() == fd) {
00184 if (i.value().watch == watch) {
00185 delete i.value().read;
00186 delete i.value().write;
00187 d->watchers.erase(i);
00188 return;
00189 }
00190 ++i;
00191 }
00192 }
00193
00194 static void qDBusToggleWatch(DBusWatch *watch, void *data)
00195 {
00196 Q_ASSERT(watch);
00197 Q_ASSERT(data);
00198
00199 QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
00200 int fd = dbus_watch_get_fd(watch);
00201
00202 QDBusConnectionPrivate::WatcherHash::iterator i = d->watchers.find(fd);
00203 while (i != d->watchers.end() && i.key() == fd) {
00204 if (i.value().watch == watch) {
00205 bool enabled = dbus_watch_get_enabled(watch);
00206 int flags = dbus_watch_get_flags(watch);
00207
00208
00209
00210 if (flags & DBUS_WATCH_READABLE && i.value().read)
00211 i.value().read->setEnabled(enabled);
00212 if (flags & DBUS_WATCH_WRITABLE && i.value().write)
00213 i.value().write->setEnabled(enabled);
00214 return;
00215 }
00216 ++i;
00217 }
00218 }
00219
00220 static void qDBusNewConnection(DBusServer *server, DBusConnection *c, void *data)
00221 {
00222 Q_ASSERT(data); Q_ASSERT(server); Q_ASSERT(c);
00223 Q_UNUSED(data); Q_UNUSED(server); Q_UNUSED(c);
00224
00225 qDebug("SERVER: GOT A NEW CONNECTION");
00226 }
00227
00228 extern QDBUS_EXPORT void qDBusAddSpyHook(QDBusSpyHook);
00229 void qDBusAddSpyHook(QDBusSpyHook hook)
00230 {
00231 qDBusSpyHookList()->append(hook);
00232 }
00233
00234 #if USE_OUTSIDE_DISPATCH
00235 # define HANDLED DBUS_HANDLER_RESULT_HANDLED_OUTSIDE_DISPATCH
00236 static DBusHandlerResult qDBusSignalFilterOutside(DBusConnection *connection,
00237 DBusMessage *message, void *data)
00238 {
00239 Q_ASSERT(data);
00240 Q_UNUSED(connection);
00241 Q_UNUSED(message);
00242
00243 QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
00244 if (d->mode == QDBusConnectionPrivate::InvalidMode)
00245 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00246
00247 CallDeliveryEvent *e = d->postedCallDeliveryEvent();
00248
00249 d->deliverCall(*e);
00250 delete e;
00251
00252 return DBUS_HANDLER_RESULT_HANDLED;
00253 }
00254 #else
00255 # define HANDLED DBUS_HANDLER_RESULT_HANDLED
00256 #endif
00257
00258 extern "C" {
00259 static DBusHandlerResult
00260 qDBusSignalFilter(DBusConnection *connection, DBusMessage *message, void *data)
00261 {
00262 return QDBusConnectionPrivate::messageFilter(connection, message, data);
00263 }
00264 }
00265
00266 DBusHandlerResult QDBusConnectionPrivate::messageFilter(DBusConnection *connection,
00267 DBusMessage *message, void *data)
00268 {
00269 Q_ASSERT(data);
00270 Q_UNUSED(connection);
00271
00272 QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
00273 if (d->mode == QDBusConnectionPrivate::InvalidMode)
00274 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00275
00276 QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(message);
00277 qDBusDebug() << "got message:" << amsg;
00278
00279 const QDBusSpyHookList *list = qDBusSpyHookList();
00280 for (int i = 0; i < list->size(); ++i) {
00281 qDBusDebug() << "calling the message spy hook";
00282 (*(*list)[i])(amsg);
00283 }
00284
00285 bool handled = false;
00286 int msgType = dbus_message_get_type(message);
00287 if (msgType == DBUS_MESSAGE_TYPE_SIGNAL) {
00288 handled = d->handleSignal(amsg);
00289 } else if (msgType == DBUS_MESSAGE_TYPE_METHOD_CALL) {
00290 handled = d->handleObjectCall(amsg);
00291 }
00292
00293 return handled ? HANDLED :
00294 DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00295 }
00296
00297 static void huntAndDestroy(QObject *needle, QDBusConnectionPrivate::ObjectTreeNode *haystack)
00298 {
00299 QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it = haystack->children.constBegin();
00300 QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator end = haystack->children.constEnd();
00301 for ( ; it != end; ++it)
00302 huntAndDestroy(needle, it->node);
00303
00304 if (needle == haystack->obj) {
00305 haystack->obj = 0;
00306 haystack->flags = 0;
00307 }
00308 }
00309
00310 static void huntAndEmit(DBusConnection *connection, DBusMessage *msg,
00311 QObject *needle, QDBusConnectionPrivate::ObjectTreeNode *haystack,
00312 bool isScriptable, bool isAdaptor, const QString &path = QString())
00313 {
00314 QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it = haystack->children.constBegin();
00315 QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator end = haystack->children.constEnd();
00316 for ( ; it != end; ++it)
00317 huntAndEmit(connection, msg, needle, it->node, isScriptable, isAdaptor, path + QLatin1String("/") + it->name);
00318
00319 if (needle == haystack->obj) {
00320
00321 if (isAdaptor && (haystack->flags & QDBusConnection::ExportAdaptors) == 0)
00322 return;
00323 else if (!isAdaptor) {
00324 int mask = isScriptable
00325 ? QDBusConnection::ExportScriptableSignals
00326 : QDBusConnection::ExportNonScriptableSignals;
00327 if ((haystack->flags & mask) == 0)
00328 return;
00329 }
00330
00331 QByteArray p = path.toLatin1();
00332 if (p.isEmpty())
00333 p = "/";
00334 qDBusDebug() << "Emitting signal at " << p;
00335 DBusMessage *msg2 = dbus_message_copy(msg);
00336 dbus_message_set_path(msg2, p);
00337 dbus_connection_send(connection, msg2, 0);
00338 dbus_message_unref(msg2);
00339 }
00340 }
00341
00342 static int findSlot(const QMetaObject *mo, const QByteArray &name, int flags,
00343 const QString &signature_, QList<int>& metaTypes)
00344 {
00345 QByteArray msgSignature = signature_.toLatin1();
00346
00347 for (int idx = mo->methodCount() - 1 ; idx >= QObject::staticMetaObject.methodCount(); --idx) {
00348 QMetaMethod mm = mo->method(idx);
00349
00350
00351 if (mm.access() != QMetaMethod::Public)
00352 continue;
00353
00354
00355
00356
00357
00358
00359
00360 QByteArray slotname = mm.signature();
00361 int paren = slotname.indexOf('(');
00362 if (paren != name.length() || !slotname.startsWith(name))
00363 continue;
00364
00365 int returnType = qDBusNameToTypeId(mm.typeName());
00366 bool isAsync = qDBusCheckAsyncTag(mm.tag());
00367 bool isScriptable = mm.attributes() & QMetaMethod::Scriptable;
00368
00369
00370 if (isAsync && returnType != QMetaType::Void)
00371 continue;
00372
00373 int inputCount = qDBusParametersForMethod(mm, metaTypes);
00374 if (inputCount == -1)
00375 continue;
00376
00377 metaTypes[0] = returnType;
00378 bool hasMessage = false;
00379 if (inputCount > 0 &&
00380 metaTypes.at(inputCount) == QDBusMetaTypeId::message) {
00381
00382 hasMessage = true;
00383 --inputCount;
00384 }
00385
00386
00387 int i;
00388 QByteArray reconstructedSignature;
00389 for (i = 1; i <= inputCount; ++i) {
00390 const char *typeSignature = QDBusMetaType::typeToSignature( metaTypes.at(i) );
00391 if (!typeSignature)
00392 break;
00393
00394 reconstructedSignature += typeSignature;
00395 if (!msgSignature.startsWith(reconstructedSignature))
00396 break;
00397 }
00398
00399 if (reconstructedSignature != msgSignature)
00400 continue;
00401
00402 if (hasMessage)
00403 ++i;
00404
00405
00406 if (returnType != 0 && QDBusMetaType::typeToSignature(returnType) == 0)
00407 continue;
00408
00409 bool ok = true;
00410 for (int j = i; ok && j < metaTypes.count(); ++j)
00411 if (QDBusMetaType::typeToSignature(metaTypes.at(i)) == 0)
00412 ok = false;
00413 if (!ok)
00414 continue;
00415
00416
00417 if (isAsync && metaTypes.count() > i + 1)
00418 continue;
00419
00420 if (isScriptable && (flags & QDBusConnection::ExportScriptableSlots) == 0)
00421 continue;
00422 if (!isScriptable && (flags & QDBusConnection::ExportNonScriptableSlots) == 0)
00423 continue;
00424
00425
00426 return idx;
00427 }
00428
00429
00430 return -1;
00431 }
00432
00433 static CallDeliveryEvent* prepareReply(QObject *object, int idx, const QList<int> &metaTypes,
00434 const QDBusMessage &msg)
00435 {
00436 Q_ASSERT(object);
00437
00438 int n = metaTypes.count() - 1;
00439 if (metaTypes[n] == QDBusMetaTypeId::message)
00440 --n;
00441
00442
00443 for (int i = 0; i < n; ++i)
00444 if (metaTypes.at(i + 1) != msg.arguments().at(i).userType() &&
00445 msg.arguments().at(i).userType() != qMetaTypeId<QDBusArgument>())
00446 return 0;
00447
00448
00449
00450 CallDeliveryEvent *data = new CallDeliveryEvent;
00451 data->object = object;
00452 data->flags = 0;
00453 data->message = msg;
00454 data->metaTypes = metaTypes;
00455 data->slotIdx = idx;
00456
00457 return data;
00458 }
00459
00460 bool QDBusConnectionPrivate::activateSignal(const QDBusConnectionPrivate::SignalHook& hook,
00461 const QDBusMessage &msg)
00462 {
00463
00464
00465
00466
00467
00468
00469
00470 CallDeliveryEvent *call = prepareReply(hook.obj, hook.midx, hook.params, msg);
00471 if (call) {
00472 postCallDeliveryEvent(call);
00473 return true;
00474 }
00475 return false;
00476 }
00477
00478 bool QDBusConnectionPrivate::activateCall(QObject* object, int flags,
00479 const QDBusMessage &msg)
00480 {
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501 if (!object)
00502 return false;
00503
00504 QList<int> metaTypes;
00505 int idx;
00506
00507 {
00508 const QMetaObject *mo = object->metaObject();
00509 QByteArray memberName = msg.member().toUtf8();
00510
00511
00512 idx = ::findSlot(mo, memberName, flags, msg.signature(), metaTypes);
00513 if (idx == -1) {
00514
00515
00516 idx = ::findSlot(mo, memberName, flags, QString(), metaTypes);
00517 if (metaTypes.count() != 2 || metaTypes.at(1) != QDBusMetaTypeId::message) {
00518 return false;
00519 }
00520 }
00521 }
00522
00523
00524
00525
00526 CallDeliveryEvent *call = new CallDeliveryEvent;
00527
00528
00529 call->object = object;
00530 call->flags = flags;
00531 call->message = msg;
00532
00533
00534 call->metaTypes = metaTypes;
00535 call->slotIdx = idx;
00536
00537 if (QDBusMessagePrivate::isLocal(msg)) {
00538
00539 sendCallDeliveryEvent(call);
00540 } else {
00541 postCallDeliveryEvent(call);
00542 }
00543
00544
00545 return true;
00546 }
00547
00548 void QDBusConnectionPrivate::sendCallDeliveryEvent(CallDeliveryEvent *data)
00549 {
00550 Q_ASSERT(data);
00551 data->conn = this;
00552 #if USE_OUTSIDE_DISPATCH
00553 callDeliveryMutex.lock();
00554 callDeliveryState = data;
00555 #else
00556 QCoreApplication::sendEvent(this, data);
00557 #endif
00558 }
00559
00560 void QDBusConnectionPrivate::postCallDeliveryEvent(CallDeliveryEvent *data)
00561 {
00562 Q_ASSERT(data);
00563 data->conn = this;
00564 #if USE_OUTSIDE_DISPATCH
00565 callDeliveryMutex.lock();
00566 callDeliveryState = data;
00567 #else
00568 QCoreApplication::postEvent(this, data);
00569 #endif
00570 }
00571
00572 CallDeliveryEvent *QDBusConnectionPrivate::postedCallDeliveryEvent()
00573 {
00574 CallDeliveryEvent *e = callDeliveryState;
00575 Q_ASSERT(e && e->conn == this);
00576
00577
00578 callDeliveryState = 0;
00579 callDeliveryMutex.unlock();
00580
00581 return e;
00582 }
00583
00584 void QDBusConnectionPrivate::deliverCall(const CallDeliveryEvent& data) const
00585 {
00586
00587 const QList<int>& metaTypes = data.metaTypes;
00588 const QDBusMessage& msg = data.message;
00589
00590 QVarLengthArray<void *, 10> params;
00591 params.reserve(metaTypes.count());
00592
00593 QVariantList auxParameters;
00594
00595
00596
00597 params.append(0);
00598
00599
00600 int i;
00601 for (i = 1; i <= qMin(msg.arguments().count(), metaTypes.count() - 1); ++i) {
00602 int id = metaTypes[i];
00603 if (id == QDBusMetaTypeId::message)
00604 break;
00605
00606 if (id == int(msg.arguments().at(i - 1).userType()))
00607
00608 params.append(const_cast<void *>(msg.arguments().at(i - 1).constData() ));
00609 else if (msg.arguments().at(i - 1).userType() == qMetaTypeId<QDBusArgument>()) {
00610
00611 void *null = 0;
00612 auxParameters.append(QVariant(id, null));
00613
00614 const QDBusArgument &in =
00615 *reinterpret_cast<const QDBusArgument *>(msg.arguments().at(i - 1).constData());
00616 QVariant &out = auxParameters[auxParameters.count() - 1];
00617
00618 if (!QDBusMetaType::demarshall(in, out.userType(), out.data()))
00619 qFatal("Internal error: demarshalling function for type '%s' (%d) failed!",
00620 out.typeName(), out.userType());
00621
00622 params.append(const_cast<void *>(out.constData()) );
00623 } else {
00624 qFatal("Internal error: got invalid meta type %d when trying to convert to meta type %d",
00625 msg.arguments().at(i - 1).userType(), id);
00626 }
00627 }
00628
00629 bool takesMessage = false;
00630 if (metaTypes.count() > i && metaTypes[i] == QDBusMetaTypeId::message) {
00631 params.append(const_cast<void*>(static_cast<const void*>(&msg)));
00632 takesMessage = true;
00633 ++i;
00634 }
00635
00636
00637 QVariantList outputArgs;
00638 void *null = 0;
00639 if (metaTypes[0] != QMetaType::Void) {
00640 QVariant arg(metaTypes[0], null);
00641 outputArgs.append( arg );
00642 params[0] = const_cast<void*>(outputArgs.at( outputArgs.count() - 1 ).constData());
00643 }
00644 for ( ; i < metaTypes.count(); ++i) {
00645 QVariant arg(metaTypes[i], null);
00646 outputArgs.append( arg );
00647 params.append(const_cast<void*>(outputArgs.at( outputArgs.count() - 1 ).constData()));
00648 }
00649
00650
00651 bool fail;
00652 if (data.object.isNull()) {
00653 fail = true;
00654 } else {
00655 QDBusConnectionPrivate::setSender(this);
00656 fail = data.object->qt_metacall(QMetaObject::InvokeMetaMethod,
00657 data.slotIdx, params.data()) >= 0;
00658 QDBusConnectionPrivate::setSender(0);
00659 }
00660
00661
00662
00663 if (QDBusMessagePrivate::isLocal(msg) && !fail) {
00664
00665
00666 QDBusMessagePrivate::setArguments(&msg, outputArgs);
00667 QDBusMessagePrivate::setType(&msg, QDBusMessage::ReplyMessage);
00668 return;
00669 }
00670
00671 if (!msg.isReplyRequired() && !msg.isDelayedReply()) {
00672 if (!fail) {
00673
00674 qDBusDebug() << "Automatically sending reply:" << outputArgs;
00675 send(msg.createReply(outputArgs));
00676 } else {
00677
00678 qWarning("Internal error: Failed to deliver message");
00679 send(QDBusMessage::createError(QDBusError(QDBusError::InternalError,
00680 QLatin1String("Failed to deliver message"))));
00681 }
00682 }
00683
00684 return;
00685 }
00686
00687 void QDBusConnectionPrivate::customEvent(QEvent *e)
00688 {
00689
00690 CallDeliveryEvent* call = static_cast<CallDeliveryEvent *>(e);
00691
00692
00693 Q_ASSERT(call->conn == this);
00694
00695 deliverCall(*call);
00696 }
00697
00698 QDBusConnectionPrivate::QDBusConnectionPrivate(QObject *p)
00699 : QObject(p), ref(1), mode(InvalidMode), connection(0), server(0), busService(0)
00700 {
00701 extern bool qDBusInitThreads();
00702 static const bool threads = qDBusInitThreads();
00703 static const bool debugging = !qgetenv("QDBUS_DEBUG").isEmpty();
00704
00705 Q_UNUSED(threads);
00706 ::isDebugging = debugging;
00707
00708 QDBusMetaTypeId::init();
00709 dbus_error_init(&error);
00710
00711 rootNode.flags = 0;
00712
00713 connect(this, SIGNAL(serviceOwnerChanged(QString,QString,QString)),
00714 this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
00715 }
00716
00717 QDBusConnectionPrivate::~QDBusConnectionPrivate()
00718 {
00719 if (dbus_error_is_set(&error))
00720 dbus_error_free(&error);
00721
00722 closeConnection();
00723 rootNode.clear();
00724 qDeleteAll(cachedMetaObjects);
00725 }
00726
00727 void QDBusConnectionPrivate::closeConnection()
00728 {
00729 QWriteLocker locker(&lock);
00730 ConnectionMode oldMode = mode;
00731 mode = InvalidMode;
00732 if (oldMode == ServerMode) {
00733 if (server) {
00734 dbus_server_disconnect(server);
00735 dbus_server_unref(server);
00736 server = 0;
00737 }
00738 } else if (oldMode == ClientMode) {
00739 if (connection) {
00740 dbus_connection_close(connection);
00741
00742 while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS)
00743 ;
00744 dbus_connection_unref(connection);
00745 connection = 0;
00746 }
00747 }
00748 }
00749
00750 bool QDBusConnectionPrivate::handleError()
00751 {
00752 lastError = QDBusError(&error);
00753 if (dbus_error_is_set(&error))
00754 dbus_error_free(&error);
00755 return lastError.isValid();
00756 }
00757
00758 void QDBusConnectionPrivate::bindToApplication()
00759 {
00760
00761 Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection",
00762 "qDBusBindToApplication called without an application");
00763 moveToThread(QCoreApplication::instance()->thread());
00764
00765
00766 WatcherHash oldWatchers = watchers;
00767 watchers.clear();
00768 QHashIterator<int, QDBusConnectionPrivate::Watcher> it(oldWatchers);
00769 while (it.hasNext()) {
00770 it.next();
00771 if (!it.value().read && !it.value().write) {
00772 qDBusAddWatch(it.value().watch, this);
00773 } else {
00774 watchers.insertMulti(it.key(), it.value());
00775 }
00776 }
00777
00778
00779 while (!pendingTimeouts.isEmpty())
00780 qDBusAddTimeout(pendingTimeouts.takeFirst(), this);
00781 }
00782
00783 void QDBusConnectionPrivate::timerEvent(QTimerEvent *e)
00784 {
00785 DBusTimeout *timeout = timeouts.value(e->timerId(), 0);
00786 dbus_timeout_handle(timeout);
00787 }
00788
00789 void QDBusConnectionPrivate::doDispatch()
00790 {
00791 if (mode == ClientMode)
00792 while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS);
00793 }
00794
00795 void QDBusConnectionPrivate::socketRead(int fd)
00796 {
00797 QHashIterator<int, QDBusConnectionPrivate::Watcher> it(watchers);
00798 while (it.hasNext()) {
00799 it.next();
00800 if (it.key() == fd && it.value().read && it.value().read->isEnabled()) {
00801 if (!dbus_watch_handle(it.value().watch, DBUS_WATCH_READABLE))
00802 qDebug("OUT OF MEM");
00803 }
00804 }
00805
00806 doDispatch();
00807 }
00808
00809 void QDBusConnectionPrivate::socketWrite(int fd)
00810 {
00811 QHashIterator<int, QDBusConnectionPrivate::Watcher> it(watchers);
00812 while (it.hasNext()) {
00813 it.next();
00814 if (it.key() == fd && it.value().write && it.value().write->isEnabled()) {
00815 if (!dbus_watch_handle(it.value().watch, DBUS_WATCH_WRITABLE))
00816 qDebug("OUT OF MEM");
00817 }
00818 }
00819 }
00820
00821 void QDBusConnectionPrivate::objectDestroyed(QObject *obj)
00822 {
00823 QWriteLocker locker(&lock);
00824 huntAndDestroy(obj, &rootNode);
00825
00826 SignalHookHash::iterator sit = signalHooks.begin();
00827 while (sit != signalHooks.end()) {
00828 if (static_cast<QObject *>(sit.value().obj) == obj)
00829 sit = signalHooks.erase(sit);
00830 else
00831 ++sit;
00832 }
00833
00834 obj->disconnect(this);
00835 }
00836
00837 void QDBusConnectionPrivate::relaySignal(QObject *obj, const QMetaObject *mo, int signalId,
00838 const QVariantList &args)
00839 {
00840 int mciid = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
00841 Q_ASSERT(mciid != -1);
00842
00843 QMetaClassInfo mci = mo->classInfo(mciid);
00844 Q_ASSERT(mci.value());
00845 const char *interface = mci.value();
00846
00847 QMetaMethod mm = mo->method(signalId);
00848 QByteArray memberName = mm.signature();
00849 memberName.truncate(memberName.indexOf('('));
00850
00851
00852 bool isScriptable = mm.attributes() & QMetaMethod::Scriptable;
00853 bool isAdaptor = false;
00854 for ( ; mo; mo = mo->superClass())
00855 if (mo == &QDBusAbstractAdaptor::staticMetaObject) {
00856 isAdaptor = true;
00857 break;
00858 }
00859
00860 QReadLocker locker(&lock);
00861 QDBusMessage message = QDBusMessage::createSignal(QLatin1String("/"), QLatin1String(interface),
00862 QLatin1String(memberName));
00863 message.setArguments(args);
00864 DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message);
00865 if (!msg) {
00866 qWarning("QDBusConnection: Could not emit signal %s.%s", interface, memberName.constData());
00867 return;
00868 }
00869
00870
00871
00872 dbus_message_set_no_reply(msg, true);
00873 huntAndEmit(connection, msg, obj, &rootNode, isScriptable, isAdaptor);
00874 dbus_message_unref(msg);
00875 }
00876
00877 void QDBusConnectionPrivate::_q_serviceOwnerChanged(const QString &name,
00878 const QString &oldOwner, const QString &newOwner)
00879 {
00880 Q_UNUSED(oldOwner);
00881
00882 if (isServiceRegisteredByThread(oldOwner))
00883 unregisterService(name);
00884 if (isServiceRegisteredByThread(newOwner))
00885 registerService(name);
00886
00887 QMutableHashIterator<QString, SignalHook> it(signalHooks);
00888 it.toFront();
00889 while (it.hasNext())
00890 if (it.next().value().service == name)
00891 it.value().owner = newOwner;
00892 }
00893
00894 int QDBusConnectionPrivate::findSlot(QObject* obj, const QByteArray &normalizedName,
00895 QList<int> ¶ms)
00896 {
00897 int midx = obj->metaObject()->indexOfMethod(normalizedName);
00898 if (midx == -1)
00899 return -1;
00900
00901 int inputCount = qDBusParametersForMethod(obj->metaObject()->method(midx), params);
00902 if ( inputCount == -1 || inputCount + 1 != params.count() )
00903 return -1;
00904
00905 return midx;
00906 }
00907
00908 bool QDBusConnectionPrivate::prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key,
00909 const QString &service, const QString &owner,
00910 const QString &path, const QString &interface, const QString &name,
00911 QObject *receiver, const char *signal, int minMIdx,
00912 bool buildSignature)
00913 {
00914 QByteArray normalizedName = signal + 1;
00915 hook.midx = findSlot(receiver, signal + 1, hook.params);
00916 if (hook.midx == -1) {
00917 normalizedName = QMetaObject::normalizedSignature(signal + 1);
00918 hook.midx = findSlot(receiver, normalizedName, hook.params);
00919 }
00920 if (hook.midx < minMIdx) {
00921 if (hook.midx == -1)
00922 ;
00923 return false;
00924 }
00925
00926 hook.service = service;
00927 hook.owner = owner;
00928 hook.path = path;
00929 hook.obj = receiver;
00930
00931
00932
00933
00934 QString mname = name;
00935 if (buildSignature && mname.isNull()) {
00936 normalizedName.truncate(normalizedName.indexOf('('));
00937 mname = QString::fromUtf8(normalizedName);
00938 }
00939 key = mname;
00940 key.reserve(interface.length() + 1 + mname.length());
00941 key += QLatin1Char(':');
00942 key += interface;
00943
00944 if (buildSignature) {
00945 hook.signature.clear();
00946 for (int i = 1; i < hook.params.count(); ++i)
00947 if (hook.params.at(i) != QDBusMetaTypeId::message)
00948 hook.signature += QLatin1String( QDBusMetaType::typeToSignature( hook.params.at(i) ) );
00949 }
00950
00951 return true;
00952 }
00953
00954 bool QDBusConnectionPrivate::activateInternalFilters(const ObjectTreeNode *node, const QDBusMessage &msg)
00955 {
00956
00957
00958 if (msg.interface().isEmpty() || msg.interface() == QLatin1String(DBUS_INTERFACE_INTROSPECTABLE)) {
00959 if (msg.member() == QLatin1String("Introspect") && msg.signature().isEmpty()) {
00960
00961 QDBusMessage reply = msg.createReply(qDBusIntrospectObject(node));
00962 if (QDBusMessagePrivate::isLocal(msg)) {
00963 QDBusMessagePrivate::setType(&msg, reply.type());
00964 QDBusMessagePrivate::setArguments(&msg, QVariantList() << qDBusIntrospectObject(node));
00965 } else {
00966 send(reply);
00967 }
00968 }
00969 if (msg.interface() == QLatin1String(DBUS_INTERFACE_INTROSPECTABLE))
00970 return true;
00971 }
00972
00973 if (node->obj && (msg.interface().isEmpty() ||
00974 msg.interface() == QLatin1String(DBUS_INTERFACE_PROPERTIES))) {
00975
00976 if (msg.member() == QLatin1String("Get") && msg.signature() == QLatin1String("ss")) {
00977 QDBusMessage reply = qDBusPropertyGet(node, msg);
00978 if (QDBusMessagePrivate::isLocal(msg)) {
00979 QDBusMessagePrivate::setType(&msg, reply.type());
00980 QDBusMessagePrivate::setArguments(&msg, reply.arguments());
00981 } else {
00982 send(reply);
00983 }
00984 } else if (msg.member() == QLatin1String("Set") && msg.signature() == QLatin1String("ssv")) {
00985 QDBusMessage reply = qDBusPropertySet(node, msg);
00986 if (QDBusMessagePrivate::isLocal(msg)) {
00987 QDBusMessagePrivate::setType(&msg, reply.type());
00988 QDBusMessagePrivate::setArguments(&msg, reply.arguments());
00989 } else {
00990 send(reply);
00991 }
00992 }
00993
00994 if (msg.interface() == QLatin1String(DBUS_INTERFACE_PROPERTIES))
00995 return true;
00996 }
00997
00998 return false;
00999 }
01000
01001 bool QDBusConnectionPrivate::activateObject(const ObjectTreeNode *node, const QDBusMessage &msg)
01002 {
01003
01004
01005
01006
01007
01008
01009
01010 QDBusAdaptorConnector *connector;
01011 if (node->flags & QDBusConnection::ExportAdaptors &&
01012 (connector = qDBusFindAdaptorConnector(node->obj))) {
01013 int newflags = node->flags | QDBusConnection::ExportNonScriptableSlots;
01014
01015 if (msg.interface().isEmpty()) {
01016
01017
01018 QDBusAdaptorConnector::AdaptorMap::ConstIterator it =
01019 connector->adaptors.constBegin();
01020 QDBusAdaptorConnector::AdaptorMap::ConstIterator end =
01021 connector->adaptors.constEnd();
01022
01023 for ( ; it != end; ++it)
01024 if (activateCall(it->adaptor, newflags, msg))
01025 return true;
01026 } else {
01027
01028 QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
01029 it = qLowerBound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
01030 msg.interface());
01031 if (it != connector->adaptors.constEnd() && msg.interface() == QLatin1String(it->interface))
01032 if (activateCall(it->adaptor, newflags, msg))
01033 return true;
01034 }
01035 }
01036
01037
01038
01039 if (activateInternalFilters(node, msg))
01040 return true;
01041
01042
01043 if (node->flags & (QDBusConnection::ExportScriptableSlots|QDBusConnection::ExportNonScriptableSlots) &&
01044 activateCall(node->obj, node->flags, msg)) {
01045 return true;
01046 }
01047 #if 0
01048
01049 qDebug("Call failed: no match for %s%s%s at %s",
01050 qPrintable(msg.interface()), msg.interface().isEmpty() ? "" : ".",
01051 qPrintable(msg.signature()),
01052 qPrintable(msg.path()));
01053 #endif
01054 return false;
01055 }
01056
01057 template<typename Func>
01058 static bool applyForObject(QDBusConnectionPrivate::ObjectTreeNode *root, const QString &fullpath,
01059 Func& functor)
01060 {
01061
01062 QStringList path = fullpath.split(QLatin1Char('/'));
01063 if (path.last().isEmpty())
01064 path.removeLast();
01065 int i = 1;
01066 QDBusConnectionPrivate::ObjectTreeNode *node = root;
01067
01068
01069 while (node && !(node->flags & QDBusConnection::ExportChildObjects) ) {
01070 if (i == path.count()) {
01071
01072 functor(node);
01073 return true;
01074 }
01075
01076 QVector<QDBusConnectionPrivate::ObjectTreeNode::Data>::ConstIterator it =
01077 qLowerBound(node->children.constBegin(), node->children.constEnd(), path.at(i));
01078 if (it != node->children.constEnd() && it->name == path.at(i))
01079
01080 node = it->node;
01081 else
01082 node = 0;
01083
01084 ++i;
01085 }
01086
01087
01088 if (node && node->flags & QDBusConnection::ExportChildObjects) {
01089 QObject *obj = node->obj;
01090
01091 while (obj) {
01092 if (i == path.count()) {
01093
01094 QDBusConnectionPrivate::ObjectTreeNode fakenode(*node);
01095 fakenode.obj = obj;
01096 functor(&fakenode);
01097 return true;
01098 }
01099
01100 const QObjectList children = obj->children();
01101
01102
01103 QObject *next = 0;
01104 QObjectList::ConstIterator it = children.constBegin();
01105 QObjectList::ConstIterator end = children.constEnd();
01106 for ( ; it != end; ++it)
01107 if ((*it)->objectName() == path.at(i)) {
01108 next = *it;
01109 break;
01110 }
01111
01112 if (!next)
01113 break;
01114
01115 ++i;
01116 obj = next;
01117 }
01118 }
01119
01120
01121 return false;
01122 }
01123
01124 #if 0
01125
01126 struct qdbus_callObject
01127 {
01128 QDBusConnectionPrivate *self;
01129 const QDBusMessage &msg;
01130 bool returnVal;
01131 inline qdbus_callObject(QDBusConnectionPrivate *s, const QDBusMessage &m)
01132 : self(s), msg(m), returnVal(false)
01133 { }
01134
01135 inline void operator()(QDBusConnectionPrivate::ObjectTreeNode *node)
01136 { }
01137 };
01138
01139 bool QDBusConnectionPrivate::doDirectObjectCall(const QDBusMessage &msg)
01140 {
01141 QReadLocker locker(&lock);
01142
01143 qdbus_callObject call(this, msg);
01144 if (applyForObject(&rootNode, msg.path(), call))
01145 return call.returnVal;
01146
01147
01148 return false;
01149 }
01150
01151 #endif
01152
01153 struct qdbus_activateObject
01154 {
01155 QDBusConnectionPrivate *self;
01156 const QDBusMessage &msg;
01157 bool returnVal;
01158 inline qdbus_activateObject(QDBusConnectionPrivate *s, const QDBusMessage &m)
01159 : self(s), msg(m), returnVal(false)
01160 { }
01161
01162 inline void operator()(QDBusConnectionPrivate::ObjectTreeNode *node)
01163 { returnVal = self->activateObject(node, msg); }
01164 };
01165
01166 bool QDBusConnectionPrivate::handleObjectCall(const QDBusMessage &msg)
01167 {
01168 QReadLocker locker(&lock);
01169
01170 qdbus_activateObject apply(this, msg);
01171 if (applyForObject(&rootNode, msg.path(), apply))
01172 return apply.returnVal;
01173
01174
01175 return false;
01176 }
01177
01178 bool QDBusConnectionPrivate::handleSignal(const QString &key, const QDBusMessage& msg)
01179 {
01180 bool result = false;
01181 SignalHookHash::const_iterator it = signalHooks.find(key);
01182 SignalHookHash::const_iterator end = signalHooks.constEnd();
01183
01184
01185 for ( ; it != end && it.key() == key; ++it) {
01186 const SignalHook &hook = it.value();
01187 if (!hook.owner.isEmpty() && hook.owner != msg.service())
01188 continue;
01189 if (!hook.path.isEmpty() && hook.path != msg.path())
01190 continue;
01191 if (!hook.signature.isEmpty() && hook.signature != msg.signature())
01192 continue;
01193 if (hook.signature.isEmpty() && !hook.signature.isNull() && !msg.signature().isEmpty())
01194 continue;
01195
01196
01197 result |= activateSignal(hook, msg);
01198 }
01199 return result;
01200 }
01201
01202 bool QDBusConnectionPrivate::handleSignal(const QDBusMessage& msg)
01203 {
01204
01205
01206
01207
01208
01209
01210
01211 QString key = msg.member();
01212 key.reserve(key.length() + 1 + msg.interface().length());
01213 key += QLatin1Char(':');
01214 key += msg.interface();
01215
01216 QReadLocker locker(&lock);
01217 bool result = handleSignal(key, msg);
01218
01219 key.truncate(msg.member().length() + 1);
01220 result |= handleSignal(key, msg);
01221
01222 key = QLatin1Char(':');
01223 key += msg.interface();
01224 result |= handleSignal(key, msg);
01225 return result;
01226 }
01227
01228 static dbus_int32_t server_slot = -1;
01229
01230 void QDBusConnectionPrivate::setServer(DBusServer *s)
01231 {
01232 if (!server) {
01233 handleError();
01234 return;
01235 }
01236
01237 server = s;
01238 mode = ServerMode;
01239
01240 dbus_server_allocate_data_slot(&server_slot);
01241 if (server_slot < 0)
01242 return;
01243
01244 dbus_server_set_watch_functions(server, qDBusAddWatch, qDBusRemoveWatch,
01245 qDBusToggleWatch, this, 0);
01246 dbus_server_set_timeout_functions(server, qDBusAddTimeout, qDBusRemoveTimeout,
01247 qDBusToggleTimeout, this, 0);
01248 dbus_server_set_new_connection_function(server, qDBusNewConnection, this, 0);
01249
01250 dbus_server_set_data(server, server_slot, this, 0);
01251 }
01252
01253 void QDBusConnectionPrivate::setConnection(DBusConnection *dbc)
01254 {
01255 if (!dbc) {
01256 handleError();
01257 return;
01258 }
01259
01260 connection = dbc;
01261 mode = ClientMode;
01262
01263 dbus_connection_set_exit_on_disconnect(connection, false);
01264 dbus_connection_set_watch_functions(connection, qDBusAddWatch, qDBusRemoveWatch,
01265 qDBusToggleWatch, this, 0);
01266 dbus_connection_set_timeout_functions(connection, qDBusAddTimeout, qDBusRemoveTimeout,
01267 qDBusToggleTimeout, this, 0);
01268
01269
01270
01271 dbus_bus_add_match(connection, "type='signal'", &error);
01272 if (handleError()) {
01273 closeConnection();
01274 return;
01275 }
01276
01277 const char *service = dbus_bus_get_unique_name(connection);
01278 if (service) {
01279 QVarLengthArray<char, 56> filter;
01280 filter.append("destination='", 13);
01281 filter.append(service, qstrlen(service));
01282 filter.append("\'\0", 2);
01283
01284 dbus_bus_add_match(connection, filter.constData(), &error);
01285 if (handleError()) {
01286 closeConnection();
01287 return;
01288 }
01289 } else {
01290 qWarning("QDBusConnectionPrivate::SetConnection: Unable to get base service");
01291 }
01292
01293 #if USE_OUTSIDE_DISPATCH
01294 dbus_connection_add_filter_outside(connection, qDBusSignalFilter, qDBusSignalFilterOutside, this, 0);
01295 #else
01296 dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0);
01297 #endif
01298
01299
01300
01301
01302 QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
01303 }
01304
01305 extern "C"{
01306 static void qDBusResultReceived(DBusPendingCall *pending, void *user_data)
01307 {
01308 QDBusConnectionPrivate::messageResultReceived(pending, user_data);
01309 }
01310 }
01311
01312 void QDBusConnectionPrivate::messageResultReceived(DBusPendingCall *pending, void *user_data)
01313 {
01314 QDBusPendingCall *call = reinterpret_cast<QDBusPendingCall *>(user_data);
01315 QDBusConnectionPrivate *connection = const_cast<QDBusConnectionPrivate *>(call->connection);
01316 Q_ASSERT(call->pending == pending);
01317
01318 if (!call->receiver.isNull() && call->methodIdx != -1) {
01319 DBusMessage *reply = dbus_pending_call_steal_reply(pending);
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329 QDBusMessage msg = QDBusMessagePrivate::fromDBusMessage(reply);
01330 qDBusDebug() << "got message: " << msg;
01331 CallDeliveryEvent *e = prepareReply(call->receiver, call->methodIdx, call->metaTypes, msg);
01332 if (e)
01333 connection->postCallDeliveryEvent(e);
01334 else
01335 qDBusDebug() << "Deliver failed!";
01336 }
01337 dbus_pending_call_unref(pending);
01338 delete call;
01339 }
01340
01341 int QDBusConnectionPrivate::send(const QDBusMessage& message) const
01342 {
01343 DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message);
01344 if (!msg) {
01345 if (message.type() == QDBusMessage::MethodCallMessage)
01346 qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\"",
01347 qPrintable(message.service()), qPrintable(message.path()),
01348 qPrintable(message.interface()), qPrintable(message.member()));
01349 else if (message.type() == QDBusMessage::SignalMessage)
01350 qWarning("QDBusConnection: error: could not send signal path \"%s\" interface \"%s\" member \"%s\"",
01351 qPrintable(message.path()), qPrintable(message.interface()),
01352 qPrintable(message.member()));
01353 else
01354 qWarning("QDBusConnection: error: could not send %s message to service \"%s\"",
01355 message.type() == QDBusMessage::ReplyMessage ? "reply" :
01356 message.type() == QDBusMessage::ErrorMessage ? "error" :
01357 "invalid", qPrintable(message.service()));
01358 return 0;
01359 }
01360
01361 dbus_message_set_no_reply(msg, true);
01362
01363 qDBusDebug() << "sending message:" << message;
01364 bool isOk = dbus_connection_send(connection, msg, 0);
01365 int serial = 0;
01366 if (isOk)
01367 serial = dbus_message_get_serial(msg);
01368
01369 dbus_message_unref(msg);
01370 return serial;
01371 }
01372
01373 QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
01374 int sendMode, int timeout)
01375 {
01376
01377 const bool localBlockingCall = ((sendMode == QDBus::BlockWithGui || sendMode == QDBus::Block)
01378 && isServiceRegisteredByThread(message.service()));
01379
01380 if (!QCoreApplication::instance() || sendMode == QDBus::Block || localBlockingCall) {
01381 DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message);
01382 if (!msg) {
01383 qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\"",
01384 qPrintable(message.service()), qPrintable(message.path()),
01385 qPrintable(message.interface()), qPrintable(message.member()));
01386 return QDBusMessage();
01387 }
01388
01389 if (localBlockingCall) {
01390 QDBusMessage messageWithSignature = QDBusMessagePrivate::updateSignature(message, msg);
01391 QDBusMessagePrivate::setLocal(&messageWithSignature, true);
01392
01393 bool handled = false;
01394 int type = dbus_message_get_type(msg);
01395 if (type == DBUS_MESSAGE_TYPE_SIGNAL)
01396 handled = handleSignal(messageWithSignature);
01397 else if (type == DBUS_MESSAGE_TYPE_METHOD_CALL)
01398 handled = handleObjectCall(messageWithSignature);
01399
01400 if (!handled)
01401 handled = activateInternalFilters(&rootNode, message);
01402 if (handled) {
01403 return messageWithSignature;
01404 } else {
01405 return QDBusMessage::createError(
01406 QString::fromLocal8Bit("InternalError"),
01407 QString::fromLocal8Bit("the sender and receiver are in the same thread"));
01408 }
01409 } else {
01410 QDBusMessage amsg;
01411 qDBusDebug() << "sending message:" << message;
01412 DBusMessage *reply = dbus_connection_send_with_reply_and_block(connection, msg, timeout, &error);
01413
01414 handleError();
01415 dbus_message_unref(msg);
01416
01417 if (lastError.isValid())
01418 return QDBusMessagePrivate::fromError(lastError);
01419
01420 amsg = QDBusMessagePrivate::fromDBusMessage(reply);
01421 dbus_message_unref(reply);
01422 qDBusDebug() << "got message:" << amsg;
01423
01424 if (dbus_connection_get_dispatch_status(connection) == DBUS_DISPATCH_DATA_REMAINS)
01425 QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
01426
01427 return amsg;
01428 }
01429 } else {
01430 QDBusReplyWaiter waiter;
01431 if (sendWithReplyAsync(message, &waiter, SLOT(reply(QDBusMessage)), timeout) > 0) {
01432
01433 waiter.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents);
01434
01435 lastError = waiter.replyMsg;
01436 return waiter.replyMsg;
01437 }
01438
01439 return QDBusMessage();
01440 }
01441 }
01442
01443 int QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
01444 const char *method, int timeout)
01445 {
01446 if (!receiver || !method || !*method) {
01447
01448 qWarning("QDBusConnection::sendWithReplyAsync: error: cannot deliver a reply to %s::%s (%s)",
01449 receiver ? receiver->metaObject()->className() : "(null)",
01450 method ? method + 1 : "(null)",
01451 receiver ? qPrintable(receiver->objectName()) : "no name");
01452 return send(message);
01453 }
01454
01455 int slotIdx = -1;
01456 QList<int> metaTypes;
01457 slotIdx = findSlot(receiver, method + 1, metaTypes);
01458 if (slotIdx == -1) {
01459 QByteArray normalizedName = QMetaObject::normalizedSignature(method + 1);
01460 slotIdx = findSlot(receiver, normalizedName, metaTypes);
01461 }
01462 if (slotIdx == -1) {
01463
01464 qWarning("QDBusConnection::sendWithReplyAsync: error: cannot deliver a reply to %s::%s (%s)",
01465 receiver->metaObject()->className(),
01466 method + 1, qPrintable(receiver->objectName()));
01467 return send(message);
01468 }
01469
01470 DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message);
01471 if (!msg) {
01472 qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\"",
01473 qPrintable(message.service()), qPrintable(message.path()),
01474 qPrintable(message.interface()), qPrintable(message.member()));
01475 return 0;
01476 }
01477
01478 qDBusDebug() << "sending message:" << message;
01479 DBusPendingCall *pending = 0;
01480 if (dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
01481 int serial = dbus_message_get_serial(msg);
01482 dbus_message_unref(msg);
01483
01484 QDBusPendingCall *pcall = new QDBusPendingCall;
01485 pcall->receiver = receiver;
01486 pcall->metaTypes = metaTypes;
01487 pcall->methodIdx = slotIdx;
01488 pcall->connection = this;
01489 pcall->pending = pending;
01490 dbus_pending_call_set_notify(pending, qDBusResultReceived, pcall, 0);
01491
01492 return serial;
01493 }
01494
01495 dbus_message_unref(msg);
01496 return 0;
01497 }
01498
01499 void QDBusConnectionPrivate::connectSignal(const QString &key, const SignalHook &hook)
01500 {
01501 signalHooks.insertMulti(key, hook);
01502 connect(hook.obj, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)));
01503 }
01504
01505 void QDBusConnectionPrivate::disconnectSignal(const QString &key, const SignalHook &hook)
01506 {
01507 hook.obj->disconnect(SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*)));
01508 signalHooks.remove(key);
01509 }
01510
01511 void QDBusConnectionPrivate::registerObject(const ObjectTreeNode *node)
01512 {
01513 connect(node->obj, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)));
01514
01515 if (node->flags & (QDBusConnection::ExportAdaptors
01516 | QDBusConnection::ExportScriptableSignals
01517 | QDBusConnection::ExportNonScriptableSignals)) {
01518 QDBusAdaptorConnector *connector = qDBusCreateAdaptorConnector(node->obj);
01519
01520 if (node->flags & (QDBusConnection::ExportScriptableSignals
01521 | QDBusConnection::ExportNonScriptableSignals)) {
01522 connector->disconnectAllSignals(node->obj);
01523 connector->connectAllSignals(node->obj);
01524 }
01525
01526
01527 connector->disconnect(SIGNAL(relaySignal(QObject*,const QMetaObject*,int,QVariantList)),
01528 this, SLOT(relaySignal(QObject*,const QMetaObject*,int,QVariantList)));
01529 connect(connector, SIGNAL(relaySignal(QObject*,const QMetaObject*,int,QVariantList)),
01530 this, SLOT(relaySignal(QObject*,const QMetaObject*,int,QVariantList)));
01531 }
01532 }
01533
01534 void QDBusConnectionPrivate::connectRelay(const QString &service, const QString &path,
01535 const QString &interface,
01536 QDBusAbstractInterface *receiver,
01537 const char *signal)
01538 {
01539
01540
01541 SignalHook hook;
01542 QString key;
01543 QString owner = getNameOwner(service);
01544
01545 if (!prepareHook(hook, key, service, owner, path, interface, QString(), receiver, signal,
01546 QDBusAbstractInterface::staticMetaObject.methodCount(), true))
01547 return;
01548
01549
01550 QWriteLocker locker(&lock);
01551 SignalHookHash::ConstIterator it = signalHooks.find(key);
01552 SignalHookHash::ConstIterator end = signalHooks.constEnd();
01553 for ( ; it != end && it.key() == key; ++it) {
01554 const SignalHook &entry = it.value();
01555 if (entry.service == hook.service &&
01556 entry.owner == hook.owner &&
01557 entry.path == hook.path &&
01558 entry.signature == hook.signature &&
01559 entry.obj == hook.obj &&
01560 entry.midx == hook.midx)
01561 return;
01562 }
01563
01564 connectSignal(key, hook);
01565 }
01566
01567 void QDBusConnectionPrivate::disconnectRelay(const QString &service, const QString &path,
01568 const QString &interface,
01569 QDBusAbstractInterface *receiver,
01570 const char *signal)
01571 {
01572
01573
01574 SignalHook hook;
01575 QString key;
01576
01577 QString owner = getNameOwner(service);
01578
01579 if (!prepareHook(hook, key, service, owner, path, interface, QString(), receiver, signal,
01580 QDBusAbstractInterface::staticMetaObject.methodCount(), true))
01581 return;
01582
01583
01584 QWriteLocker locker(&lock);
01585 SignalHookHash::Iterator it = signalHooks.find(key);
01586 SignalHookHash::Iterator end = signalHooks.end();
01587 for ( ; it != end && it.key() == key; ++it) {
01588 const SignalHook &entry = it.value();
01589 if (entry.service == hook.service &&
01590 entry.owner == hook.owner &&
01591 entry.path == hook.path &&
01592 entry.signature == hook.signature &&
01593 entry.obj == hook.obj &&
01594 entry.midx == hook.midx) {
01595
01596 signalHooks.erase(it);
01597 return;
01598 }
01599 }
01600
01601 qWarning("QDBusConnectionPrivate::disconnectRelay called for a signal that was not found");
01602 }
01603
01604 QString QDBusConnectionPrivate::getNameOwner(const QString& serviceName)
01605 {
01606 if (QDBusUtil::isValidUniqueConnectionName(serviceName))
01607 return serviceName;
01608 if (!connection || !QDBusUtil::isValidBusName(serviceName))
01609 return QString();
01610
01611 QDBusMessage msg = QDBusMessage::createMethodCall(QLatin1String(DBUS_SERVICE_DBUS),
01612 QLatin1String(DBUS_PATH_DBUS), QLatin1String(DBUS_INTERFACE_DBUS),
01613 QLatin1String("GetNameOwner"));
01614 msg << serviceName;
01615 QDBusMessage reply = sendWithReply(msg, QDBus::Block);
01616 if (!lastError.isValid() && reply.type() == QDBusMessage::ReplyMessage)
01617 return reply.arguments().at(0).toString();
01618 return QString();
01619 }
01620
01621 struct qdbus_Introspect
01622 {
01623 QString xml;
01624 inline void operator()(QDBusConnectionPrivate::ObjectTreeNode *node)
01625 { xml = qDBusIntrospectObject(node); }
01626 };
01627
01628 QDBusMetaObject *
01629 QDBusConnectionPrivate::findMetaObject(const QString &service, const QString &path,
01630 const QString &interface)
01631 {
01632
01633 if (!interface.isEmpty()) {
01634 QReadLocker locker(&lock);
01635 QDBusMetaObject *mo = cachedMetaObjects.value(interface, 0);
01636 if (mo)
01637 return mo;
01638 }
01639 if (service == QLatin1String(dbus_bus_get_unique_name(connection))) {
01640
01641 QWriteLocker locker(&lock);
01642 QDBusMetaObject *mo = 0;
01643 if (!interface.isEmpty())
01644 mo = cachedMetaObjects.value(interface, 0);
01645 if (mo)
01646
01647 return mo;
01648
01649 qdbus_Introspect apply;
01650 if (!applyForObject(&rootNode, path, apply)) {
01651 lastError = QDBusError(QDBusError::InvalidArgs,
01652 QString(QLatin1String("No object at %1")).arg(path));
01653 return 0;
01654 }
01655
01656
01657 return QDBusMetaObject::createMetaObject(interface, apply.xml, cachedMetaObjects, lastError);
01658 }
01659
01660
01661 QDBusMessage msg = QDBusMessage::createMethodCall(service, path,
01662 QLatin1String(DBUS_INTERFACE_INTROSPECTABLE),
01663 QLatin1String("Introspect"));
01664
01665 QDBusMessage reply = sendWithReply(msg, QDBus::Block);
01666
01667
01668 QWriteLocker locker(&lock);
01669 QDBusMetaObject *mo = 0;
01670 if (!interface.isEmpty())
01671 mo = cachedMetaObjects.value(interface, 0);
01672 if (mo)
01673
01674 return mo;
01675
01676 QString xml;
01677 if (reply.type() == QDBusMessage::ReplyMessage)
01678
01679 xml = reply.arguments().at(0).toString();
01680 else {
01681 lastError = reply;
01682 if (reply.type() != QDBusMessage::ErrorMessage || lastError.type() != QDBusError::UnknownMethod)
01683 return 0;
01684 }
01685
01686
01687 return QDBusMetaObject::createMetaObject(interface, xml, cachedMetaObjects, lastError);
01688 }
01689
01690 void QDBusConnectionPrivate::registerService(const QString &serviceName)
01691 {
01692 qDBusServicesRegisteredByThread()->append(serviceName);
01693 }
01694
01695 void QDBusConnectionPrivate::unregisterService(const QString &serviceName)
01696 {
01697 qDBusServicesRegisteredByThread()->removeAll(serviceName);
01698 }
01699
01700 bool QDBusConnectionPrivate::isServiceRegisteredByThread(const QString &serviceName) const
01701 {
01702 return (serviceName == baseService() || qDBusServicesRegisteredByThread()->contains(serviceName));
01703 }
01704
01705 QString QDBusConnectionPrivate::baseService() const
01706 {
01707 return connection ?
01708 QString::fromUtf8(dbus_bus_get_unique_name(connection))
01709 : QString();
01710 }
01711
01712 void QDBusReplyWaiter::reply(const QDBusMessage &msg)
01713 {
01714 replyMsg = msg;
01715 quit();
01716 }