* dbus/dbus-sysdeps.c: Make tcp socket connection error somewhat more
[platform/upstream/dbus.git] / qt / qdbusconnection.cpp
1 /* qdbusconnection.cpp
2  *
3  * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
4  * Copyright (C) 2006 Trolltech AS. All rights reserved.
5  *    Author: Thiago Macieira <thiago.macieira@trolltech.com>
6  *
7  * Licensed under the Academic Free License version 2.1
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation
21  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  *
23  */
24
25 #include <qdebug.h>
26 #include <qcoreapplication.h>
27 #include <qstringlist.h>
28
29 #include "qdbusbus.h"
30 #include "qdbusconnection.h"
31 #include "qdbuserror.h"
32 #include "qdbusmessage.h"
33 #include "qdbusconnection_p.h"
34 #include "qdbusinterface_p.h"
35 #include "qdbusutil.h"
36
37 class QDBusConnectionManager
38 {
39 public:
40     QDBusConnectionManager() {}
41     ~QDBusConnectionManager();
42     void bindToApplication();
43     QDBusConnectionPrivate *connection(const QString &name) const;
44     void removeConnection(const QString &name);
45     void setConnection(const QString &name, QDBusConnectionPrivate *c);
46
47 private:
48     mutable QMutex mutex;
49     QHash<QString, QDBusConnectionPrivate *> connectionHash;
50 };
51
52 Q_GLOBAL_STATIC(QDBusConnectionManager, manager);
53
54 QDBusConnectionPrivate *QDBusConnectionManager::connection(const QString &name) const
55 {
56     QMutexLocker locker(&mutex);
57     return connectionHash.value(name, 0);
58 }
59
60 void QDBusConnectionManager::removeConnection(const QString &name)
61 {
62     QMutexLocker locker(&mutex);
63
64     QDBusConnectionPrivate *d = 0;
65     d = connectionHash.take(name);
66     if (d && !d->ref.deref())
67         delete d;
68 }
69
70 QDBusConnectionManager::~QDBusConnectionManager()
71 {
72     for (QHash<QString, QDBusConnectionPrivate *>::const_iterator it = connectionHash.constBegin();
73          it != connectionHash.constEnd(); ++it) {
74              delete it.value();
75     }
76     connectionHash.clear();
77 }
78
79 void QDBusConnectionManager::bindToApplication()
80 {
81     QMutexLocker locker(&mutex);
82     for (QHash<QString, QDBusConnectionPrivate *>::const_iterator it = connectionHash.constBegin();
83          it != connectionHash.constEnd(); ++it) {
84              (*it)->bindToApplication();
85     }
86 }
87
88 QDBUS_EXPORT void qDBusBindToApplication();
89 void qDBusBindToApplication()
90 {
91     manager()->bindToApplication();
92 }
93
94 void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionPrivate *c)
95 {
96     connectionHash[name] = c;
97     c->name = name;
98 }
99
100 /*!
101     \fn QDBusConnection QDBus::sessionBus()
102     \relates QDBusConnection
103
104     Returns a QDBusConnection object opened with the session bus. The object reference returned
105     by this function is valid until the QCoreApplication's destructor is run, when the
106     connection will be closed and the object, deleted.
107 */
108 /*!
109     \fn QDBusConnection QDBus::systemBus()
110     \relates QDBusConnection
111
112     Returns a QDBusConnection object opened with the system bus. The object reference returned
113     by this function is valid until the QCoreApplication's destructor is run, when the
114     connection will be closed and the object, deleted.
115 */
116
117 /*!
118     \class QDBusConnection
119     \brief A connection to the D-Bus bus daemon.
120
121     This class is the initial point in a D-Bus session. Using it, you can get access to remote
122     objects, interfaces; connect remote signals to your object's slots; register objects, etc.
123
124     D-Bus connections are created using the QDBusConnection::addConnection() function, which opens a
125     connection to the server daemon and does the initial handshaking, associating that connection
126     with a name. Further attempts to connect using the same name will return the same
127     connection.
128
129     The connection is then torn down using the QDBusConnection::closeConnection() function.
130
131     As a convenience for the two most common connection types, the QDBus::sessionBus() and
132     QDBus::systemBus() functions return open connections to the session server daemon and the system
133     server daemon, respectively. Those connections are opened when first used and are closed when
134     the QCoreApplication destructor is run.
135
136     D-Bus also supports peer-to-peer connections, without the need for a bus server daemon. Using
137     this facility, two applications can talk to each other and exchange messages. This can be
138     achieved by passing an address to QDBusConnection::addConnection()
139     function, which was opened by another D-Bus application using QDBusServer.
140 */
141
142 /*!
143     \enum QDBusConnection::BusType
144     Specifies the type of the bus connection. The valid bus types are:
145
146     \value SessionBus           the session bus, associated with the running desktop session
147     \value SystemBus            the system bus, used to communicate with system-wide processes
148     \value ActivationBus        the activation bus, whose purpose I have no idea...
149
150     On the Session Bus, one can find other applications by the same user that are sharing the same
151     desktop session (hence the name). On the System Bus, however, processes shared for the whole
152     system are usually found.
153 */
154
155 /*!
156     \enum QDBusConnection::WaitMode
157     Specifies the call waiting mode.
158
159     \value UseEventLoop         use the Qt Event Loop to wait for the reply
160     \value NoUseEventLoop       don't use the event loop
161
162     The \c UseEventLoop option allows for the application to continue to update its UI while the
163     call is performed, but it also opens up the possibility for reentrancy: socket notifiers may
164     fire, signals may be delivered and other D-Bus calls may be processed. The \c NoUseEventLoop
165     does not use the event loop, thus being safe from those problems, but it may block the
166     application for a noticeable period of time, in case the remote application fails to respond.
167
168     Also note that calls that go back to the local application can only be placed in \c UseEventLoop
169     mode.
170 */
171
172 /*!
173     \enum QDBusConnection::RegisterOption
174     Specifies the options for registering objects with the connection. The possible values are:
175
176     \value ExportAdaptors                       export the contents of adaptors found in this object
177
178     \value ExportSlots                          export this object's scriptable slots
179     \value ExportSignals                        export this object's scriptable signals
180     \value ExportProperties                     export this object's scriptable properties
181     \value ExportContents                       shorthand form for ExportSlots | ExportSignals |
182                                                 ExportProperties
183
184     \value ExportAllSlots                       export all of this object's slots, including
185                                                 non-scriptable ones
186     \value ExportAllSignals                     export all of this object's signals, including
187                                                 non-scriptable ones
188     \value ExportAllProperties                  export all of this object's properties, including
189                                                 non-scriptable ones
190     \value ExportAllContents                    export all of this object's slots, signals and
191                                                 properties, including non-scriptable ones
192
193     \value ExportChildObjects                   export this object's child objects
194
195     \warning It is currently not possible to export signals from objects. If you pass the flag
196     ExportSignals or ExportAllSignals, the registerObject() function will print a warning.
197
198     \sa registerObject(), QDBusAbstractAdaptor, {usingadaptors.html}{Using adaptors}
199 */
200
201 /*!
202     \enum QDBusConnection::UnregisterMode
203     The mode for unregistering an object path:
204
205     \value UnregisterNode       unregister this node only: do not unregister child objects
206     \value UnregisterTree       unregister this node and all its sub-tree
207
208     Note, however, if this object was registered with the ExportChildObjects option, UnregisterNode
209     will unregister the child objects too.
210 */
211
212 /*!
213     Creates a QDBusConnection object attached to the connection with name \a name.
214
215     This does not open the connection. You have to call QDBusConnection::addConnection to open it.
216 */
217 QDBusConnection::QDBusConnection(const QString &name)
218 {
219     d = manager()->connection(name);
220     if (d)
221         d->ref.ref();
222 }
223
224 /*!
225     Creates a copy of the \a other connection.
226 */
227 QDBusConnection::QDBusConnection(const QDBusConnection &other)
228 {
229     d = other.d;
230     if (d)
231         d->ref.ref();
232 }
233
234 /*!
235     Disposes of this object. This does not close the connection: you have to call
236     QDBusConnection::closeConnection to do that.
237 */
238 QDBusConnection::~QDBusConnection()
239 {
240     if (d && !d->ref.deref())
241         delete d;
242 }
243
244 /*!
245     Creates a copy of the connection \a other in this object. The connection this object referenced
246     before the copy is not spontaneously disconnected. See QDBusConnection::closeConnection for more
247     information.
248 */
249 QDBusConnection &QDBusConnection::operator=(const QDBusConnection &other)
250 {
251     if (other.d)
252         other.d->ref.ref();
253     QDBusConnectionPrivate *old = static_cast<QDBusConnectionPrivate *>(
254             q_atomic_set_ptr(&d, other.d));
255     if (old && !old->ref.deref())
256         delete old;
257
258     return *this;
259 }
260
261 /*!
262     Opens a connection of type \a type to one of the known busses and associate with it the
263     connection name \a name. Returns a QDBusConnection object associated with that connection.
264 */
265 QDBusConnection QDBusConnection::addConnection(BusType type, const QString &name)
266 {
267 //    Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection",
268 //               "Cannot create connection without a Q[Core]Application instance");
269
270     QDBusConnectionPrivate *d = manager()->connection(name);
271     if (d || name.isEmpty())
272         return QDBusConnection(name);
273
274     d = new QDBusConnectionPrivate;
275     DBusConnection *c = 0;
276     switch (type) {
277         case SystemBus:
278             c = dbus_bus_get(DBUS_BUS_SYSTEM, &d->error);
279             break;
280         case SessionBus:
281             c = dbus_bus_get(DBUS_BUS_SESSION, &d->error);
282             break;
283         case ActivationBus:
284             c = dbus_bus_get(DBUS_BUS_STARTER, &d->error);
285             break;
286     }
287     d->setConnection(c); //setConnection does the error handling for us
288
289     manager()->setConnection(name, d);
290
291     QDBusConnection retval(name);
292
293     // create the bus service
294     QDBusAbstractInterfacePrivate *p;
295     p = retval.findInterface_helper(QLatin1String(DBUS_SERVICE_DBUS),
296                                     QLatin1String(DBUS_PATH_DBUS),
297                                     QLatin1String(DBUS_INTERFACE_DBUS));
298     if (p) {
299         d->busService = new QDBusBusService(p);
300         d->busService->setParent(d); // auto-deletion
301         d->ref.deref();              // busService has a increased the refcounting to us
302     }
303
304     return retval;
305 }
306
307 /*!
308     Opens a peer-to-peer connection on address \a address and associate with it the
309     connection name \a name. Returns a QDBusConnection object associated with that connection.
310 */
311 QDBusConnection QDBusConnection::addConnection(const QString &address,
312                     const QString &name)
313 {
314 //    Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection",
315 //               "Cannot create connection without a Q[Core]Application instance");
316
317     QDBusConnectionPrivate *d = manager()->connection(name);
318     if (d || name.isEmpty())
319         return QDBusConnection(name);
320
321     d = new QDBusConnectionPrivate;
322     // setConnection does the error handling for us
323     d->setConnection(dbus_connection_open(address.toUtf8().constData(), &d->error));
324
325     manager()->setConnection(name, d);
326
327     QDBusConnection retval(name);
328
329     // create the bus service
330     QDBusAbstractInterfacePrivate *p;
331     p = retval.findInterface_helper(QLatin1String(DBUS_SERVICE_DBUS),
332                                     QLatin1String(DBUS_PATH_DBUS),
333                                     QLatin1String(DBUS_INTERFACE_DBUS));
334     if (p) {
335         d->busService = new QDBusBusService(p);
336         d->busService->setParent(d); // auto-deletion
337         d->ref.deref();              // busService has a increased the refcounting to us
338     }
339
340     return retval;
341 }
342
343 /*!
344     Closes the connection of name \a name.
345
346     Note that if there are still QDBusConnection objects associated with the same connection, the
347     connection will not be closed until all references are dropped. However, no further references
348     can be created using the QDBusConnection::QDBusConnection constructor.
349 */
350 void QDBusConnection::closeConnection(const QString &name)
351 {
352     manager()->removeConnection(name);
353 }
354
355 /*!
356     Sends the \a message over this connection, without waiting for a reply. This is suitable for
357     errors, signals, and return values as well as calls whose return values are not necessary.
358
359     Returns true if the message was queued successfully, false otherwise.
360 */
361 bool QDBusConnection::send(const QDBusMessage &message) const
362 {
363     if (!d || !d->connection)
364         return false;
365     return d->send(message) != 0;
366 }
367
368 /*!
369     Sends the \a message over this connection and returns immediately after queueing it. When the
370     reply is received, the slot \a method is called in the object \a receiver. This function is
371     suitable for method calls only.
372
373     This function guarantees that the slot will be called exactly once with the reply, as long as
374     the parameter types match. If they don't, the reply cannot be delivered.
375
376     Returns the identification of the message that was sent or 0 if nothing was sent.
377 */
378 int QDBusConnection::sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
379         const char *method) const
380 {
381     if (!d || !d->connection)
382         return 0;
383
384     return d->sendWithReplyAsync(message, receiver, method);
385 }
386
387 /*!
388     Sends the \a message over this connection and blocks, waiting for a reply. This function is
389     suitable for method calls only. It returns the reply message as its return value, which will be
390     either of type QDBusMessage::ReplyMessage or QDBusMessage::ErrorMessage.
391
392     See the QDBusInterface::call function for a more friendly way of placing calls.
393
394     \warning If \a mode is \c UseEventLoop, this function will reenter the Qt event loop in order to
395              wait for the reply. During the wait, it may deliver signals and other method calls to
396              your application. Therefore, it must be prepared to handle a reentrancy whenever a call
397              is placed with sendWithReply.
398 */
399 QDBusMessage QDBusConnection::sendWithReply(const QDBusMessage &message, WaitMode mode) const
400 {
401     if (!d || !d->connection)
402         return QDBusMessage();
403     return d->sendWithReply(message, mode);
404 }
405
406 /*!
407     Connects the signal specified by the \a service, \a path, \a interface and \a name parameters to
408     the slot \a slot in object \a receiver. The arguments \a service and \a path can be empty,
409     denoting a connection to any signal of the \a interface - \a name pair, from any remote
410     application.
411
412     Returns true if the connection was successful.
413
414     \warning The signal will only be delivered to the slot if the parameters match. This verification
415              can be done only when the signal is received, not at connection time.
416 */
417 bool QDBusConnection::connect(const QString &service, const QString &path, const QString& interface,
418                               const QString &name, QObject *receiver, const char *slot)
419 {
420     return connect(service, path, interface, name, QString(), receiver, slot);
421 }
422
423 /*!
424     \overload
425     Connects the signal to the slot \a slot in object \a receiver. Unlike the other
426     QDBusConnection::connect overload, this function allows one to specify the parameter signature
427     to be connected using the \a signature variable. The function will then verify that this
428     signature can be delivered to the slot specified by \a slot and return false otherwise.
429 */
430 bool QDBusConnection::connect(const QString &service, const QString &path, const QString& interface,
431                               const QString &name, const QString &signature,
432                               QObject *receiver, const char *slot)
433 {
434     if (!receiver || !slot || !d || !d->connection || !QDBusUtil::isValidInterfaceName(interface))
435         return false;
436
437     QString source;
438     if (!service.isEmpty()) {
439         source = d->getNameOwner(service);
440         if (source.isEmpty())
441             return false;
442     }
443
444     // check the slot
445     QDBusConnectionPrivate::SignalHook hook;
446     QString key;
447     hook.signature = signature;
448     if (!d->prepareHook(hook, key, source, path, interface, name, receiver, slot, 0, false))
449         return false;           // don't connect
450
451     // avoid duplicating:
452     QWriteLocker locker(&d->lock);
453     QDBusConnectionPrivate::SignalHookHash::ConstIterator it = d->signalHooks.find(key);
454     for ( ; it != d->signalHooks.end() && it.key() == key; ++it) {
455         const QDBusConnectionPrivate::SignalHook &entry = it.value();
456         if (entry.sender == hook.sender &&
457             entry.path == hook.path &&
458             entry.signature == hook.signature &&
459             entry.obj == hook.obj &&
460             entry.midx == hook.midx) {
461             // no need to compare the parameters if it's the same slot
462             return true;        // already there
463         }
464     }
465
466
467     d->connectSignal(key, hook);
468     return true;
469 }
470
471 /*!
472     Registers the object \a object at path \a path and returns true if the registration was
473     successful. The \a options parameter specifies how much of the object \a object will be exposed
474     through D-Bus.
475
476     This function does not replace existing objects: if there is already an object registered at
477     path \a path, this function will return false. Use unregisterObject() to unregister it first.
478
479     You cannot register an object as a child object of an object that was registered with
480     QDBusConnection::ExportChildObjects.
481 */
482 bool QDBusConnection::registerObject(const QString &path, QObject *object, RegisterOptions options)
483 {
484     if (!d || !d->connection || !object || !options || !QDBusUtil::isValidObjectPath(path))
485         return false;
486
487     if (options & ExportSignals) {
488         qWarning("Cannot export signals from objects. Use an adaptor for that purpose.");
489         return false;
490     }
491
492     QStringList pathComponents = path.split(QLatin1Char('/'));
493     if (pathComponents.last().isEmpty())
494         pathComponents.removeLast();
495     QWriteLocker locker(&d->lock);
496
497     // lower-bound search for where this object should enter in the tree
498     QDBusConnectionPrivate::ObjectTreeNode *node = &d->rootNode;
499     int i = 1;
500     while (node) {
501         if (pathComponents.count() == i) {
502             // this node exists
503             // consider it free if there's no object here and the user is not trying to
504             // replace the object sub-tree
505             if ((options & ExportChildObjects && !node->children.isEmpty()) || node->obj)
506                 return false;
507
508             // we can add the object here
509             node->obj = object;
510             node->flags = options;
511
512             d->registerObject(node);
513             qDebug("REGISTERED FOR %s", path.toLocal8Bit().constData());
514             return true;
515         }
516
517         // find the position where we'd insert the node
518         QVector<QDBusConnectionPrivate::ObjectTreeNode::Data>::Iterator it =
519             qLowerBound(node->children.begin(), node->children.end(), pathComponents.at(i));
520         if (it != node->children.constEnd() && it->name == pathComponents.at(i)) {
521             // match: this node exists
522             node = it->node;
523
524             // are we allowed to go deeper?
525             if (node->flags & ExportChildObjects) {
526                 // we're not
527                 qDebug("Cannot register object at %s because %s exports its own child objects",
528                        qPrintable(path), qPrintable(pathComponents.at(i)));
529                 return false;
530             }
531         } else {
532             // add entry
533             QDBusConnectionPrivate::ObjectTreeNode::Data entry;
534             entry.name = pathComponents.at(i);
535             entry.node = new QDBusConnectionPrivate::ObjectTreeNode;
536             node->children.insert(it, entry);
537
538             node = entry.node;
539         }
540
541         // iterate
542         ++i;
543     }
544
545     Q_ASSERT_X(false, "QDBusConnection::registerObject", "The impossible happened");
546     return false;
547 }
548
549 /*!
550     Unregisters an object that was registered with the registerObject() at the object path given by
551     \a path and, if \a mode is QDBusConnection::UnregisterTree, all of its sub-objects too.
552
553     Note that you cannot unregister objects that were not registered with registerObject().
554 */
555 void QDBusConnection::unregisterObject(const QString &path, UnregisterMode mode)
556 {
557     if (!d || !d->connection || !QDBusUtil::isValidObjectPath(path))
558         return;
559
560     QStringList pathComponents = path.split(QLatin1Char('/'));
561     QWriteLocker locker(&d->lock);
562     QDBusConnectionPrivate::ObjectTreeNode *node = &d->rootNode;
563     int i = 1;
564
565     // find the object
566     while (node) {
567         if (pathComponents.count() == i) {
568             // found it
569             node->obj = 0;
570             node->flags = 0;
571
572             if (mode == UnregisterTree) {
573                 // clear the sub-tree as well
574                 node->clear();  // can't disconnect the objects because we really don't know if they can
575                                 // be found somewhere else in the path too
576             }
577
578             return;
579         }
580
581         QVector<QDBusConnectionPrivate::ObjectTreeNode::Data>::ConstIterator it =
582             qLowerBound(node->children.constBegin(), node->children.constEnd(), pathComponents.at(i));
583         if (it == node->children.constEnd() || it->name != pathComponents.at(i))
584             break;              // node not found
585
586         node = it->node;
587         ++i;
588     }
589 }
590
591 /*!
592     Returns a dynamic QDBusInterface associated with the interface \a interface on object at path \a
593     path on service \a service.
594
595     This function creates a new object. It is your resposibility to ensure it is properly deleted
596     (you can use all normal QObject deletion mechanisms, including the QObject::deleteLater() slot
597     and QObject::setParent()).
598
599     If the searching for this interface on the remote object failed, this function returns 0.
600 */
601 QDBusInterface *QDBusConnection::findInterface(const QString& service, const QString& path,
602                                                const QString& interface)
603 {
604     if (!d)
605         return 0;
606     
607     QDBusInterfacePrivate *p = d->findInterface(service, path, interface);
608     QDBusInterface *retval = new QDBusInterface(p);
609     retval->setParent(d);
610     return retval;
611 }
612
613 /*!
614     \fn QDBusConnection::findInterface(const QString &service, const QString &path)
615     Returns an interface of type \c Interface associated with the object on path \a path at service
616     \a service.
617
618     \c Interface must be a class generated by \l {dbusidl2cpp.html}.
619
620     This function creates a new object. It is your resposibility to ensure it is properly deleted
621     (you can use all normal QObject deletion mechanisms, including the QObject::deleteLater() slot
622     and QObject::setParent()).
623 */
624
625 /*!
626     Returns a QDBusBusService object that represents the D-Bus bus service on this connection.
627
628     This function returns 0 for peer-to-peer connections.
629 */
630 QDBusBusService *QDBusConnection::busService() const
631 {
632     if (!d)
633         return 0;
634     return d->busService;
635 };
636
637 QDBusAbstractInterfacePrivate *
638 QDBusConnection::findInterface_helper(const QString &service, const QString &path,
639                                       const QString &interface)
640 {
641     if (!d)
642         return 0;
643     if (!interface.isEmpty() && !QDBusUtil::isValidInterfaceName(interface))
644         return 0;
645     
646     QString owner;
647     if (!service.isEmpty()) {
648         if (!QDBusUtil::isValidObjectPath(path))
649             return 0;
650
651         // check if it's there first -- FIXME: add binding mode
652         owner = d->getNameOwner(service);
653         if (owner.isEmpty())
654             return 0;
655     } else if (!path.isEmpty())
656         return 0;
657     
658     return new QDBusAbstractInterfacePrivate(*this, d, owner, path, interface);
659 }
660
661 /*!
662     Returns true if this QDBusConnection object is connected.
663
664     If it isn't connected, calling QDBusConnection::addConnection on the same connection name
665     will not make be connected. You need to call the QDBusConnection constructor again.
666 */
667 bool QDBusConnection::isConnected( ) const
668 {
669     return d && d->connection && dbus_connection_get_is_connected(d->connection);
670 }
671
672 /*!
673     Returns the last error that happened in this connection.
674
675     This function is provided for low-level code. If you're using QDBusInterface::call, error codes are
676     reported by its return value.
677
678     \sa QDBusInterface, QDBusMessage
679 */
680 QDBusError QDBusConnection::lastError() const
681 {
682     return d ? d->lastError : QDBusError();
683 }
684
685 /*!
686     Returns the unique connection name for this connection, if this QDBusConnection object is
687     connected, or an empty QString otherwise.
688
689     A Unique Connection Name is a string in the form ":x.xxx" (where x are decimal digits) that is
690     assigned by the D-Bus server daemon upon connection. It uniquely identifies this client in the
691     bus.
692
693     This function returns an empty QString for peer-to-peer connections.
694 */
695 QString QDBusConnection::baseService() const
696 {
697     return d && d->connection ?
698             QString::fromUtf8(dbus_bus_get_unique_name(d->connection))
699             : QString();
700 }
701
702 Q_GLOBAL_STATIC(QMutex, defaultBussesMutex);
703 static const char sessionBusName[] = "qt_default_session_bus";
704 static const char systemBusName[] = "qt_default_system_bus";
705 static QDBusConnection *sessionBus = 0;
706 static QDBusConnection *systemBus = 0;
707
708 static void closeConnections()
709 {
710     QMutexLocker locker(defaultBussesMutex());
711     delete sessionBus;
712     delete systemBus;
713     QDBusConnection::closeConnection(QLatin1String(sessionBusName));
714     QDBusConnection::closeConnection(QLatin1String(systemBusName));
715     sessionBus = systemBus = 0;
716 }
717
718 static QDBusConnection *openConnection(QDBusConnection::BusType type)
719 {
720     QMutexLocker locker(defaultBussesMutex());
721     qAddPostRoutine(closeConnections);
722     
723     if (type == QDBusConnection::SystemBus) {
724         if (systemBus)
725             // maybe it got created before we locked the mutex
726             return systemBus;
727         systemBus = new QDBusConnection(QDBusConnection::addConnection(QDBusConnection::SystemBus,
728                            QLatin1String(systemBusName)));
729         return systemBus;
730     } else {
731         if (sessionBus)
732             // maybe it got created before we locked the mutex
733             return sessionBus;
734         sessionBus = new QDBusConnection(QDBusConnection::addConnection(QDBusConnection::SessionBus,
735                            QLatin1String(sessionBusName)));
736         return sessionBus;
737     }
738 }
739
740 namespace QDBus {
741     QDBusConnection &sessionBus()
742     {
743         if (::sessionBus) return *::sessionBus;
744         return *openConnection(QDBusConnection::SessionBus);
745     }
746
747     QDBusConnection &systemBus()
748     {
749         if (::systemBus) return *::systemBus;
750         return *openConnection(QDBusConnection::SystemBus);
751     }
752 }
753