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