connection.cpp
Go to the documentation of this file.
1/*
2 *
3 * D-Bus++ - C++ bindings for D-Bus
4 *
5 * Copyright (C) 2005-2007 Paolo Durante <shackan@gmail.com>
6 *
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include <dbus-c++/debug.h>
29#include <dbus-c++/connection.h>
30
31#include <dbus/dbus.h>
32#include <string>
33
34#include "internalerror.h"
35
36#include "connection_p.h"
37#include "dispatcher_p.h"
38#include "server_p.h"
39#include "message_p.h"
40#include "pendingcall_p.h"
41
42using namespace DBus;
43
44Connection::Private::Private(DBusConnection *c, Server::Private *s)
45 : conn(c) , dispatcher(NULL), server(s)
46{
47 init();
48}
49
50Connection::Private::Private(DBusBusType type)
51 : dispatcher(NULL), server(NULL)
52{
54
55 conn = dbus_bus_get_private(type, e);
56
57 if (e) throw Error(e);
58
59 init();
60}
61
62Connection::Private::~Private()
63{
64 debug_log("terminating connection 0x%08x", conn);
65
66 detach_server();
67
68 if (dbus_connection_get_is_connected(conn))
69 {
70 std::vector<std::string>::iterator i = names.begin();
71
72 while (i != names.end())
73 {
74 debug_log("%s: releasing bus name %s", dbus_bus_get_unique_name(conn), i->c_str());
75 dbus_bus_release_name(conn, i->c_str(), NULL);
76 ++i;
77 }
78 dbus_connection_close(conn);
79 }
80 dbus_connection_unref(conn);
81}
82
83void Connection::Private::init()
84{
85 dbus_connection_ref(conn);
86 dbus_connection_ref(conn); //todo: the library has to own another reference
87
89 this, &Connection::Private::disconn_filter_function
90 );
91
92 dbus_connection_add_filter(conn, message_filter_stub, &disconn_filter, NULL); // TODO: some assert at least
93
94 dbus_connection_set_dispatch_status_function(conn, dispatch_status_stub, this, 0);
95 dbus_connection_set_exit_on_disconnect(conn, false); //why was this set to true??
96}
97
98void Connection::Private::detach_server()
99{
100 /* Server::Private *tmp = server;
101
102 server = NULL;
103
104 if (tmp)
105 {
106 ConnectionList::iterator i;
107
108 for (i = tmp->connections.begin(); i != tmp->connections.end(); ++i)
109 {
110 if (i->_pvt.get() == this)
111 {
112 tmp->connections.erase(i);
113 break;
114 }
115 }
116 }*/
117}
118
119bool Connection::Private::do_dispatch()
120{
121 debug_log("dispatching on %p", conn);
122
123 if (!dbus_connection_get_is_connected(conn))
124 {
125 debug_log("connection terminated");
126
127 detach_server();
128
129 return true;
130 }
131
132 return dbus_connection_dispatch(conn) != DBUS_DISPATCH_DATA_REMAINS;
133}
134
135void Connection::Private::dispatch_status_stub(DBusConnection *dc, DBusDispatchStatus status, void *data)
136{
137 Private *p = static_cast<Private *>(data);
138
139 switch (status)
140 {
141 case DBUS_DISPATCH_DATA_REMAINS:
142 debug_log("some dispatching to do on %p", dc);
143 p->dispatcher->queue_connection(p);
144 break;
145
146 case DBUS_DISPATCH_COMPLETE:
147 debug_log("all dispatching done on %p", dc);
148 break;
149
150 case DBUS_DISPATCH_NEED_MEMORY: //uh oh...
151 debug_log("connection %p needs memory", dc);
152 break;
153 }
154}
155
156DBusHandlerResult Connection::Private::message_filter_stub(DBusConnection *conn, DBusMessage *dmsg, void *data)
157{
158 MessageSlot *slot = static_cast<MessageSlot *>(data);
159
160 Message msg = Message(new Message::Private(dmsg));
161
162 return slot && !slot->empty() && slot->call(msg)
163 ? DBUS_HANDLER_RESULT_HANDLED
164 : DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
165}
166
167bool Connection::Private::disconn_filter_function(const Message &msg)
168{
169 if (msg.is_signal(DBUS_INTERFACE_LOCAL, "Disconnected"))
170 {
171 debug_log("%p disconnected by local bus", conn);
172 dbus_connection_close(conn);
173
174 return true;
175 }
176 return false;
177}
178
179DBusDispatchStatus Connection::Private::dispatch_status()
180{
181 return dbus_connection_get_dispatch_status(conn);
182}
183
184bool Connection::Private::has_something_to_dispatch()
185{
186 return dispatch_status() == DBUS_DISPATCH_DATA_REMAINS;
187}
188
189
190Connection Connection::SystemBus()
191{
192 return Connection(new Private(DBUS_BUS_SYSTEM));
193}
194
196{
197 return Connection(new Private(DBUS_BUS_SESSION));
198}
199
201{
202 return Connection(new Private(DBUS_BUS_STARTER));
203}
204
205Connection::Connection(const char *address, bool priv)
206 : _timeout(-1)
207{
209 DBusConnection *conn = priv
210 ? dbus_connection_open_private(address, e)
211 : dbus_connection_open(address, e);
212
213 if (e) throw Error(e);
214
215 _pvt = new Private(conn);
216
218
219 debug_log("connected to %s", address);
220}
221
223 : _pvt(p), _timeout(-1)
224{
226}
227
229 : _pvt(c._pvt), _timeout(c._timeout)
230{
231 dbus_connection_ref(_pvt->conn);
232}
233
235{
236 dbus_connection_unref(_pvt->conn);
237}
238
240{
241 debug_log("registering stubs for connection %p", _pvt->conn);
242
244
245 if (!dispatcher) throw ErrorFailed("no default dispatcher set for new connection");
246
247 Dispatcher *prev = _pvt->dispatcher;
248
249 _pvt->dispatcher = dispatcher;
250
252
253 dbus_connection_set_watch_functions(
254 _pvt->conn,
255 Dispatcher::Private::on_add_watch,
256 Dispatcher::Private::on_rem_watch,
257 Dispatcher::Private::on_toggle_watch,
259 0
260 );
261
262 dbus_connection_set_timeout_functions(
263 _pvt->conn,
264 Dispatcher::Private::on_add_timeout,
265 Dispatcher::Private::on_rem_timeout,
266 Dispatcher::Private::on_toggle_timeout,
268 0
269 );
270
271 return prev;
272}
273
275{
276 return _pvt->conn == c._pvt->conn;
277}
278
280{
282
283 bool r = dbus_bus_register(_pvt->conn, e);
284
285 if (e) throw(e);
286
287 return r;
288}
289
291{
292 return dbus_connection_get_is_connected(_pvt->conn);
293}
294
296{
297// dbus_connection_disconnect(_pvt->conn); // disappeared in 0.9x
298 dbus_connection_close(_pvt->conn);
299}
300
302{
303 dbus_connection_set_exit_on_disconnect(_pvt->conn, exit);
304}
305
306bool Connection::unique_name(const char *n)
307{
308 return dbus_bus_set_unique_name(_pvt->conn, n);
309}
310
311const char *Connection::unique_name() const
312{
313 return dbus_bus_get_unique_name(_pvt->conn);
314}
315
317{
318 dbus_connection_flush(_pvt->conn);
319}
320
321void Connection::add_match(const char *rule)
322{
324
325 dbus_bus_add_match(_pvt->conn, rule, e);
326
327 debug_log("%s: added match rule %s", unique_name(), rule);
328
329 if (e) throw Error(e);
330}
331
332void Connection::remove_match(const char *rule,
333 bool throw_on_error)
334{
336
337 dbus_bus_remove_match(_pvt->conn, rule, e);
338
339 debug_log("%s: removed match rule %s", unique_name(), rule);
340
341 if (e)
342 {
343 if (throw_on_error)
344 throw Error(e);
345 else
346 debug_log("DBus::Connection::remove_match: %s (%s).",
347 static_cast<DBusError *>(e)->message,
348 static_cast<DBusError *>(e)->name);
349 }
350}
351
353{
354 debug_log("%s: adding filter", unique_name());
355 return dbus_connection_add_filter(_pvt->conn, Private::message_filter_stub, &s, NULL);
356}
357
359{
360 debug_log("%s: removing filter", unique_name());
361 dbus_connection_remove_filter(_pvt->conn, Private::message_filter_stub, &s);
362}
363
364bool Connection::send(const Message &msg, unsigned int *serial)
365{
366 return dbus_connection_send(_pvt->conn, msg._pvt->msg, serial);
367}
368
370{
371 DBusMessage *reply;
373
374 if (this->_timeout != -1)
375 {
376 reply = dbus_connection_send_with_reply_and_block(_pvt->conn, msg._pvt->msg, this->_timeout, e);
377 }
378 else
379 {
380 reply = dbus_connection_send_with_reply_and_block(_pvt->conn, msg._pvt->msg, timeout, e);
381 }
382
383 if (e) throw Error(e);
384
385 return Message(new Message::Private(reply), false);
386}
387
389{
390 DBusPendingCall *pending;
391
392 if (!dbus_connection_send_with_reply(_pvt->conn, msg._pvt->msg, &pending, timeout))
393 {
394 throw ErrorNoMemory("Unable to start asynchronous call");
395 }
396 return PendingCall(new PendingCall::Private(pending));
397}
398
399void Connection::request_name(const char *name, int flags)
400{
402
403 debug_log("%s: registering bus name %s", unique_name(), name);
404
405 /*
406 * TODO:
407 * Think about giving back the 'ret' value. Some people on the list
408 * requested about this...
409 */
410 int ret = dbus_bus_request_name(_pvt->conn, name, flags, e);
411
412 if (ret == -1)
413 {
414 if (e) throw Error(e);
415 }
416
417// this->remove_match("destination");
418
419 if (name)
420 {
421 _pvt->names.push_back(name);
422 std::string match = "destination='" + _pvt->names.back() + "'";
423 add_match(match.c_str());
424 }
425}
426
427unsigned long Connection::sender_unix_uid(const char *sender)
428{
430
431 unsigned long ul = dbus_bus_get_unix_user(_pvt->conn, sender, e);
432
433 if (e) throw Error(e);
434
435 return ul;
436}
437
438bool Connection::has_name(const char *name)
439{
441
442 bool b = dbus_bus_name_has_owner(_pvt->conn, name, e);
443
444 if (e) throw Error(e);
445
446 return b;
447}
448
449const std::vector<std::string>& Connection::names()
450{
451 return _pvt->names;
452}
453
454bool Connection::start_service(const char *name, unsigned long flags)
455{
457
458 bool b = dbus_bus_start_service_by_name(_pvt->conn, name, flags, NULL, e);
459
460 if (e) throw Error(e);
461
462 return b;
463}
464
465void Connection::set_timeout(int timeout)
466{
467 _timeout = timeout;
468}
469
471{
472 return _timeout;
473}
474
T * get() const
Definition: util.h:145
R call(P param) const
Definition: util.h:248
bool empty() const
Definition: util.h:260
DXXAPI Dispatcher * default_dispatcher
Definition: dispatcher.cpp:36
DXXAPI LogFunction debug_log
Definition: debug.cpp:55
bool connected() const
Gets whether the connection is currently open.
Definition: connection.cpp:290
void exit_on_disconnect(bool exit)
Set whether _exit() should be called when the connection receives a disconnect signal.
Definition: connection.cpp:301
Connection(Private *)
void remove_match(const char *rule, bool throw_on_error)
Removes a previously-added match rule "by value" (the most recently-added identical rule gets removed...
Definition: connection.cpp:332
bool has_name(const char *name)
Asks the bus whether a certain name has an owner.
Definition: connection.cpp:438
Private(DBusConnection *, Server::Private *=NULL)
void flush()
Blocks until the outgoing message queue is empty.
Definition: connection.cpp:316
void request_name(const char *name, int flags=0)
Definition: connection.cpp:399
Message send_blocking(Message &msg, int timeout=-1)
Sends a message and blocks a certain time period while waiting for a reply.
Definition: connection.cpp:369
virtual ~Connection()
Definition: connection.cpp:234
bool add_filter(MessageSlot &s)
Adds a message filter.
Definition: connection.cpp:352
Dispatcher * setup(Dispatcher *)
Definition: connection.cpp:239
Dispatcher * dispatcher
Definition: connection_p.h:50
bool start_service(const char *name, unsigned long flags)
Starts a service that will request ownership of the given name.
Definition: connection.cpp:454
void remove_filter(MessageSlot &s)
Removes a previously-added message filter.
Definition: connection.cpp:358
void add_match(const char *rule)
Adds a match rule to match messages going through the message bus.
Definition: connection.cpp:321
static Connection ActivationBus()
Definition: connection.cpp:200
bool send(const Message &msg, unsigned int *serial=NULL)
Adds a message to the outgoing message queue.
Definition: connection.cpp:364
unsigned long sender_unix_uid(const char *sender)
Definition: connection.cpp:427
RefPtrI< Private > _pvt
Definition: connection.h:461
PendingCall send_async(Message &msg, int timeout=-1)
Queues a message to send, as with send(), but also returns a DBusPendingCall used to receive a reply ...
Definition: connection.cpp:388
static Connection SessionBus()
Definition: connection.cpp:195
bool register_bus()
Registers a connection with the bus.
Definition: connection.cpp:279
DBusConnection * conn
Definition: connection_p.h:46
void set_timeout(int timeout)
Definition: connection.cpp:465
bool operator==(const Connection &) const
Definition: connection.cpp:274
void disconnect()
Closes a private connection, so no further data can be sent or received.
Definition: connection.cpp:295
std::vector< std::string > names
Definition: connection_p.h:48
const char * unique_name() const
Gets the unique name of the connection as assigned by the message bus.
Definition: connection.cpp:311
void queue_connection(Connection::Private *)
Definition: dispatcher.cpp:158
RefPtrI< Private > _pvt
Definition: message.h:208
bool is_signal(const char *interface, const char *member) const
Definition: message.cpp:468
friend struct Private
Definition: pendingcall.h:127