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 
42 using namespace DBus;
43 
44 Connection::Private::Private(DBusConnection *c, Server::Private *s)
45  : conn(c) , dispatcher(NULL), server(s)
46 {
47  init();
48 }
49 
50 Connection::Private::Private(DBusBusType type)
51  : dispatcher(NULL), server(NULL)
52 {
53  InternalError e;
54 
55  conn = dbus_bus_get_private(type, e);
56 
57  if (e) throw Error(e);
58 
59  init();
60 }
61 
62 Connection::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 
83 void 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  dbus_connection_set_unix_user_function (conn, 0, 0, 0);
97 }
98 
99 void Connection::Private::detach_server()
100 {
101  /* Server::Private *tmp = server;
102 
103  server = NULL;
104 
105  if (tmp)
106  {
107  ConnectionList::iterator i;
108 
109  for (i = tmp->connections.begin(); i != tmp->connections.end(); ++i)
110  {
111  if (i->_pvt.get() == this)
112  {
113  tmp->connections.erase(i);
114  break;
115  }
116  }
117  }*/
118 }
119 
120 bool Connection::Private::do_dispatch()
121 {
122  debug_log("dispatching on %p", conn);
123 
124  if (!dbus_connection_get_is_connected(conn))
125  {
126  debug_log("connection terminated");
127 
128  detach_server();
129 
130  return true;
131  }
132 
133  return dbus_connection_dispatch(conn) != DBUS_DISPATCH_DATA_REMAINS;
134 }
135 
136 void Connection::Private::dispatch_status_stub(DBusConnection *dc, DBusDispatchStatus status, void *data)
137 {
138  Private *p = static_cast<Private *>(data);
139 
140  switch (status)
141  {
142  case DBUS_DISPATCH_DATA_REMAINS:
143  debug_log("some dispatching to do on %p", dc);
144  p->dispatcher->queue_connection(p);
145  break;
146 
147  case DBUS_DISPATCH_COMPLETE:
148  debug_log("all dispatching done on %p", dc);
149  break;
150 
151  case DBUS_DISPATCH_NEED_MEMORY: //uh oh...
152  debug_log("connection %p needs memory", dc);
153  break;
154  }
155 }
156 
157 DBusHandlerResult Connection::Private::message_filter_stub(DBusConnection *conn, DBusMessage *dmsg, void *data)
158 {
159  MessageSlot *slot = static_cast<MessageSlot *>(data);
160 
161  Message msg = Message(new Message::Private(dmsg));
162 
163  return slot && !slot->empty() && slot->call(msg)
164  ? DBUS_HANDLER_RESULT_HANDLED
165  : DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
166 }
167 
168 bool Connection::Private::disconn_filter_function(const Message &msg)
169 {
170  if (msg.is_signal(DBUS_INTERFACE_LOCAL, "Disconnected"))
171  {
172  debug_log("%p disconnected by local bus", conn);
173  dbus_connection_close(conn);
174 
175  return true;
176  }
177  return false;
178 }
179 
180 DBusDispatchStatus Connection::Private::dispatch_status()
181 {
182  return dbus_connection_get_dispatch_status(conn);
183 }
184 
185 bool Connection::Private::has_something_to_dispatch()
186 {
187  return dispatch_status() == DBUS_DISPATCH_DATA_REMAINS;
188 }
189 
190 
191 Connection Connection::SystemBus()
192 {
193  return Connection(new Private(DBUS_BUS_SYSTEM));
194 }
195 
197 {
198  return Connection(new Private(DBUS_BUS_SESSION));
199 }
200 
202 {
203  return Connection(new Private(DBUS_BUS_STARTER));
204 }
205 
206 Connection::Connection(const char *address, bool priv)
207  : _timeout(-1)
208 {
209  InternalError e;
210  DBusConnection *conn = priv
211  ? dbus_connection_open_private(address, e)
212  : dbus_connection_open(address, e);
213 
214  if (e) throw Error(e);
215 
216  _pvt = new Private(conn);
217 
219 
220  debug_log("connected to %s", address);
221 }
222 
224  : _pvt(p), _timeout(-1)
225 {
227 }
228 
230  : _pvt(c._pvt), _timeout(c._timeout)
231 {
232  dbus_connection_ref(_pvt->conn);
233 }
234 
236 {
237  dbus_connection_unref(_pvt->conn);
238 }
239 
241 {
242  debug_log("registering stubs for connection %p", _pvt->conn);
243 
245 
246  if (!dispatcher) throw ErrorFailed("no default dispatcher set for new connection");
247 
248  Dispatcher *prev = _pvt->dispatcher;
249 
250  _pvt->dispatcher = dispatcher;
251 
253 
254  dbus_connection_set_watch_functions(
255  _pvt->conn,
256  Dispatcher::Private::on_add_watch,
257  Dispatcher::Private::on_rem_watch,
258  Dispatcher::Private::on_toggle_watch,
259  dispatcher,
260  0
261  );
262 
263  dbus_connection_set_timeout_functions(
264  _pvt->conn,
265  Dispatcher::Private::on_add_timeout,
266  Dispatcher::Private::on_rem_timeout,
267  Dispatcher::Private::on_toggle_timeout,
268  dispatcher,
269  0
270  );
271 
272  return prev;
273 }
274 
276 {
277  return _pvt->conn == c._pvt->conn;
278 }
279 
281 {
282  InternalError e;
283 
284  bool r = dbus_bus_register(_pvt->conn, e);
285 
286  if (e) throw(e);
287 
288  return r;
289 }
290 
292 {
293  return dbus_connection_get_is_connected(_pvt->conn);
294 }
295 
297 {
298 // dbus_connection_disconnect(_pvt->conn); // disappeared in 0.9x
299  dbus_connection_close(_pvt->conn);
300 }
301 
303 {
304  dbus_connection_set_exit_on_disconnect(_pvt->conn, exit);
305 }
306 
307 bool Connection::unique_name(const char *n)
308 {
309  return dbus_bus_set_unique_name(_pvt->conn, n);
310 }
311 
312 const char *Connection::unique_name() const
313 {
314  return dbus_bus_get_unique_name(_pvt->conn);
315 }
316 
318 {
319  dbus_connection_flush(_pvt->conn);
320 }
321 
322 void Connection::add_match(const char *rule)
323 {
324  InternalError e;
325 
326  dbus_bus_add_match(_pvt->conn, rule, e);
327 
328  debug_log("%s: added match rule %s", unique_name(), rule);
329 
330  if (e) throw Error(e);
331 }
332 
333 void Connection::remove_match(const char *rule,
334  bool throw_on_error)
335 {
336  InternalError e;
337 
338  dbus_bus_remove_match(_pvt->conn, rule, e);
339 
340  debug_log("%s: removed match rule %s", unique_name(), rule);
341 
342  if (e)
343  {
344  if (throw_on_error)
345  throw Error(e);
346  else
347  debug_log("DBus::Connection::remove_match: %s (%s).",
348  static_cast<DBusError *>(e)->message,
349  static_cast<DBusError *>(e)->name);
350  }
351 }
352 
354 {
355  debug_log("%s: adding filter", unique_name());
356  return dbus_connection_add_filter(_pvt->conn, Private::message_filter_stub, &s, NULL);
357 }
358 
360 {
361  debug_log("%s: removing filter", unique_name());
362  dbus_connection_remove_filter(_pvt->conn, Private::message_filter_stub, &s);
363 }
364 
365 bool Connection::send(const Message &msg, unsigned int *serial)
366 {
367  return dbus_connection_send(_pvt->conn, msg._pvt->msg, serial);
368 }
369 
371 {
372  DBusMessage *reply;
373  InternalError e;
374 
375  if (this->_timeout != -1)
376  {
377  reply = dbus_connection_send_with_reply_and_block(_pvt->conn, msg._pvt->msg, this->_timeout, e);
378  }
379  else
380  {
381  reply = dbus_connection_send_with_reply_and_block(_pvt->conn, msg._pvt->msg, timeout, e);
382  }
383 
384  if (e) throw Error(e);
385 
386  return Message(new Message::Private(reply), false);
387 }
388 
390 {
391  DBusPendingCall *pending;
392 
393  if (!dbus_connection_send_with_reply(_pvt->conn, msg._pvt->msg, &pending, timeout))
394  {
395  throw ErrorNoMemory("Unable to start asynchronous call");
396  }
397  return PendingCall(new PendingCall::Private(pending));
398 }
399 
400 void Connection::request_name(const char *name, int flags)
401 {
402  InternalError e;
403 
404  debug_log("%s: registering bus name %s", unique_name(), name);
405 
406  /*
407  * TODO:
408  * Think about giving back the 'ret' value. Some people on the list
409  * requested about this...
410  */
411  int ret = dbus_bus_request_name(_pvt->conn, name, flags, e);
412 
413  if (ret == -1)
414  {
415  if (e) throw Error(e);
416  }
417 
418 // this->remove_match("destination");
419 
420  if (name)
421  {
422  _pvt->names.push_back(name);
423  std::string match = "destination='" + _pvt->names.back() + "'";
424  add_match(match.c_str());
425  }
426 }
427 
428 unsigned long Connection::sender_unix_uid(const char *sender)
429 {
430  InternalError e;
431 
432  unsigned long ul = dbus_bus_get_unix_user(_pvt->conn, sender, e);
433 
434  if (e) throw Error(e);
435 
436  return ul;
437 }
438 
439 bool Connection::has_name(const char *name)
440 {
441  InternalError e;
442 
443  bool b = dbus_bus_name_has_owner(_pvt->conn, name, e);
444 
445  if (e) throw Error(e);
446 
447  return b;
448 }
449 
450 const std::vector<std::string>& Connection::names()
451 {
452  return _pvt->names;
453 }
454 
455 bool Connection::start_service(const char *name, unsigned long flags)
456 {
457  InternalError e;
458 
459  bool b = dbus_bus_start_service_by_name(_pvt->conn, name, flags, NULL, e);
460 
461  if (e) throw Error(e);
462 
463  return b;
464 }
465 
466 void Connection::set_timeout(int timeout)
467 {
468  _timeout = timeout;
469 }
470 
472 {
473  return _timeout;
474 }
475 
void remove_filter(MessageSlot &s)
Removes a previously-added message filter.
Definition: connection.cpp:359
virtual ~Connection()
Definition: connection.cpp:235
R call(P param) const
Definition: util.h:249
RefPtrI< Private > _pvt
Definition: connection.h:461
void add_match(const char *rule)
Adds a match rule to match messages going through the message bus.
Definition: connection.cpp:322
void queue_connection(Connection::Private *)
Definition: dispatcher.cpp:158
void disconnect()
Closes a private connection, so no further data can be sent or received.
Definition: connection.cpp:296
bool register_bus()
Registers a connection with the bus.
Definition: connection.cpp:280
bool add_filter(MessageSlot &s)
Adds a message filter.
Definition: connection.cpp:353
Dispatcher * dispatcher
Definition: connection_p.h:50
const char * unique_name() const
Gets the unique name of the connection as assigned by the message bus.
Definition: connection.cpp:312
bool has_name(const char *name)
Asks the bus whether a certain name has an owner.
Definition: connection.cpp:439
Private(DBusServer *)
T * get() const
Definition: util.h:145
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:389
void set_timeout(int timeout)
Definition: connection.cpp:466
bool is_signal(const char *interface, const char *member) const
Definition: message.cpp:467
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:333
static Connection SessionBus()
Definition: connection.cpp:196
static Connection ActivationBus()
Definition: connection.cpp:201
DXXAPI LogFunction debug_log
Definition: debug.cpp:55
RefPtrI< Private > _pvt
Definition: message.h:208
DXXAPI Dispatcher * default_dispatcher
Definition: dispatcher.cpp:36
void flush()
Blocks until the outgoing message queue is empty.
Definition: connection.cpp:317
unsigned long sender_unix_uid(const char *sender)
Definition: connection.cpp:428
DBusConnection * conn
Definition: connection_p.h:46
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:370
bool start_service(const char *name, unsigned long flags)
Starts a service that will request ownership of the given name.
Definition: connection.cpp:455
Dispatcher * setup(Dispatcher *)
Definition: connection.cpp:240
std::vector< std::string > names
Definition: connection_p.h:48
Private(DBusConnection *, Server::Private *=NULL)
bool empty() const
Definition: util.h:263
bool connected() const
Gets whether the connection is currently open.
Definition: connection.cpp:291
bool operator==(const Connection &) const
Definition: connection.cpp:275
Connection(Private *)
bool send(const Message &msg, unsigned int *serial=NULL)
Adds a message to the outgoing message queue.
Definition: connection.cpp:365
friend struct Private
Definition: pendingcall.h:127
void request_name(const char *name, int flags=0)
Definition: connection.cpp:400
void exit_on_disconnect(bool exit)
Set whether _exit() should be called when the connection receives a disconnect signal.
Definition: connection.cpp:302