00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027
00028 #include <dbus-c++/debug.h>
00029 #include <dbus-c++/connection.h>
00030
00031 #include <dbus/dbus.h>
00032 #include <string>
00033
00034 #include "internalerror.h"
00035
00036 #include "connection_p.h"
00037 #include "dispatcher_p.h"
00038 #include "server_p.h"
00039 #include "message_p.h"
00040 #include "pendingcall_p.h"
00041
00042 using namespace DBus;
00043
00044 Connection::Private::Private(DBusConnection *c, Server::Private *s)
00045 : conn(c) , dispatcher(NULL), server(s)
00046 {
00047 init();
00048 }
00049
00050 Connection::Private::Private(DBusBusType type)
00051 : dispatcher(NULL), server(NULL)
00052 {
00053 InternalError e;
00054
00055 conn = dbus_bus_get_private(type, e);
00056
00057 if (e) throw Error(e);
00058
00059 init();
00060 }
00061
00062 Connection::Private::~Private()
00063 {
00064 debug_log("terminating connection 0x%08x", conn);
00065
00066 detach_server();
00067
00068 if (dbus_connection_get_is_connected(conn))
00069 {
00070 std::vector<std::string>::iterator i = names.begin();
00071
00072 while (i != names.end())
00073 {
00074 debug_log("%s: releasing bus name %s", dbus_bus_get_unique_name(conn), i->c_str());
00075 dbus_bus_release_name(conn, i->c_str(), NULL);
00076 ++i;
00077 }
00078 dbus_connection_close(conn);
00079 }
00080 dbus_connection_unref(conn);
00081 }
00082
00083 void Connection::Private::init()
00084 {
00085 dbus_connection_ref(conn);
00086 dbus_connection_ref(conn);
00087
00088 disconn_filter = new Callback<Connection::Private, bool, const Message &>(
00089 this, &Connection::Private::disconn_filter_function
00090 );
00091
00092 dbus_connection_add_filter(conn, message_filter_stub, &disconn_filter, NULL);
00093
00094 dbus_connection_set_dispatch_status_function(conn, dispatch_status_stub, this, 0);
00095 dbus_connection_set_exit_on_disconnect(conn, false);
00096 }
00097
00098 void Connection::Private::detach_server()
00099 {
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117 }
00118
00119 bool Connection::Private::do_dispatch()
00120 {
00121 debug_log("dispatching on %p", conn);
00122
00123 if (!dbus_connection_get_is_connected(conn))
00124 {
00125 debug_log("connection terminated");
00126
00127 detach_server();
00128
00129 return true;
00130 }
00131
00132 return dbus_connection_dispatch(conn) != DBUS_DISPATCH_DATA_REMAINS;
00133 }
00134
00135 void Connection::Private::dispatch_status_stub(DBusConnection *dc, DBusDispatchStatus status, void *data)
00136 {
00137 Private *p = static_cast<Private *>(data);
00138
00139 switch (status)
00140 {
00141 case DBUS_DISPATCH_DATA_REMAINS:
00142 debug_log("some dispatching to do on %p", dc);
00143 p->dispatcher->queue_connection(p);
00144 break;
00145
00146 case DBUS_DISPATCH_COMPLETE:
00147 debug_log("all dispatching done on %p", dc);
00148 break;
00149
00150 case DBUS_DISPATCH_NEED_MEMORY:
00151 debug_log("connection %p needs memory", dc);
00152 break;
00153 }
00154 }
00155
00156 DBusHandlerResult Connection::Private::message_filter_stub(DBusConnection *conn, DBusMessage *dmsg, void *data)
00157 {
00158 MessageSlot *slot = static_cast<MessageSlot *>(data);
00159
00160 Message msg = Message(new Message::Private(dmsg));
00161
00162 return slot && !slot->empty() && slot->call(msg)
00163 ? DBUS_HANDLER_RESULT_HANDLED
00164 : DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00165 }
00166
00167 bool Connection::Private::disconn_filter_function(const Message &msg)
00168 {
00169 if (msg.is_signal(DBUS_INTERFACE_LOCAL, "Disconnected"))
00170 {
00171 debug_log("%p disconnected by local bus", conn);
00172 dbus_connection_close(conn);
00173
00174 return true;
00175 }
00176 return false;
00177 }
00178
00179 DBusDispatchStatus Connection::Private::dispatch_status()
00180 {
00181 return dbus_connection_get_dispatch_status(conn);
00182 }
00183
00184 bool Connection::Private::has_something_to_dispatch()
00185 {
00186 return dispatch_status() == DBUS_DISPATCH_DATA_REMAINS;
00187 }
00188
00189
00190 Connection Connection::SystemBus()
00191 {
00192 return Connection(new Private(DBUS_BUS_SYSTEM));
00193 }
00194
00195 Connection Connection::SessionBus()
00196 {
00197 return Connection(new Private(DBUS_BUS_SESSION));
00198 }
00199
00200 Connection Connection::ActivationBus()
00201 {
00202 return Connection(new Private(DBUS_BUS_STARTER));
00203 }
00204
00205 Connection::Connection(const char *address, bool priv)
00206 : _timeout(-1)
00207 {
00208 InternalError e;
00209 DBusConnection *conn = priv
00210 ? dbus_connection_open_private(address, e)
00211 : dbus_connection_open(address, e);
00212
00213 if (e) throw Error(e);
00214
00215 _pvt = new Private(conn);
00216
00217 setup(default_dispatcher);
00218
00219 debug_log("connected to %s", address);
00220 }
00221
00222 Connection::Connection(Connection::Private *p)
00223 : _pvt(p), _timeout(-1)
00224 {
00225 setup(default_dispatcher);
00226 }
00227
00228 Connection::Connection(const Connection &c)
00229 : _pvt(c._pvt), _timeout(c._timeout)
00230 {
00231 dbus_connection_ref(_pvt->conn);
00232 }
00233
00234 Connection::~Connection()
00235 {
00236 dbus_connection_unref(_pvt->conn);
00237 }
00238
00239 Dispatcher *Connection::setup(Dispatcher *dispatcher)
00240 {
00241 debug_log("registering stubs for connection %p", _pvt->conn);
00242
00243 if (!dispatcher) dispatcher = default_dispatcher;
00244
00245 if (!dispatcher) throw ErrorFailed("no default dispatcher set for new connection");
00246
00247 Dispatcher *prev = _pvt->dispatcher;
00248
00249 _pvt->dispatcher = dispatcher;
00250
00251 dispatcher->queue_connection(_pvt.get());
00252
00253 dbus_connection_set_watch_functions(
00254 _pvt->conn,
00255 Dispatcher::Private::on_add_watch,
00256 Dispatcher::Private::on_rem_watch,
00257 Dispatcher::Private::on_toggle_watch,
00258 dispatcher,
00259 0
00260 );
00261
00262 dbus_connection_set_timeout_functions(
00263 _pvt->conn,
00264 Dispatcher::Private::on_add_timeout,
00265 Dispatcher::Private::on_rem_timeout,
00266 Dispatcher::Private::on_toggle_timeout,
00267 dispatcher,
00268 0
00269 );
00270
00271 return prev;
00272 }
00273
00274 bool Connection::operator == (const Connection &c) const
00275 {
00276 return _pvt->conn == c._pvt->conn;
00277 }
00278
00279 bool Connection::register_bus()
00280 {
00281 InternalError e;
00282
00283 bool r = dbus_bus_register(_pvt->conn, e);
00284
00285 if (e) throw(e);
00286
00287 return r;
00288 }
00289
00290 bool Connection::connected() const
00291 {
00292 return dbus_connection_get_is_connected(_pvt->conn);
00293 }
00294
00295 void Connection::disconnect()
00296 {
00297
00298 dbus_connection_close(_pvt->conn);
00299 }
00300
00301 void Connection::exit_on_disconnect(bool exit)
00302 {
00303 dbus_connection_set_exit_on_disconnect(_pvt->conn, exit);
00304 }
00305
00306 bool Connection::unique_name(const char *n)
00307 {
00308 return dbus_bus_set_unique_name(_pvt->conn, n);
00309 }
00310
00311 const char *Connection::unique_name() const
00312 {
00313 return dbus_bus_get_unique_name(_pvt->conn);
00314 }
00315
00316 void Connection::flush()
00317 {
00318 dbus_connection_flush(_pvt->conn);
00319 }
00320
00321 void Connection::add_match(const char *rule)
00322 {
00323 InternalError e;
00324
00325 dbus_bus_add_match(_pvt->conn, rule, e);
00326
00327 debug_log("%s: added match rule %s", unique_name(), rule);
00328
00329 if (e) throw Error(e);
00330 }
00331
00332 void Connection::remove_match(const char *rule,
00333 bool throw_on_error)
00334 {
00335 InternalError e;
00336
00337 dbus_bus_remove_match(_pvt->conn, rule, e);
00338
00339 debug_log("%s: removed match rule %s", unique_name(), rule);
00340
00341 if (e)
00342 {
00343 if (throw_on_error)
00344 throw Error(e);
00345 else
00346 debug_log("DBus::Connection::remove_match: %s (%s).",
00347 static_cast<DBusError *>(e)->message,
00348 static_cast<DBusError *>(e)->name);
00349 }
00350 }
00351
00352 bool Connection::add_filter(MessageSlot &s)
00353 {
00354 debug_log("%s: adding filter", unique_name());
00355 return dbus_connection_add_filter(_pvt->conn, Private::message_filter_stub, &s, NULL);
00356 }
00357
00358 void Connection::remove_filter(MessageSlot &s)
00359 {
00360 debug_log("%s: removing filter", unique_name());
00361 dbus_connection_remove_filter(_pvt->conn, Private::message_filter_stub, &s);
00362 }
00363
00364 bool Connection::send(const Message &msg, unsigned int *serial)
00365 {
00366 return dbus_connection_send(_pvt->conn, msg._pvt->msg, serial);
00367 }
00368
00369 Message Connection::send_blocking(Message &msg, int timeout)
00370 {
00371 DBusMessage *reply;
00372 InternalError e;
00373
00374 if (this->_timeout != -1)
00375 {
00376 reply = dbus_connection_send_with_reply_and_block(_pvt->conn, msg._pvt->msg, this->_timeout, e);
00377 }
00378 else
00379 {
00380 reply = dbus_connection_send_with_reply_and_block(_pvt->conn, msg._pvt->msg, timeout, e);
00381 }
00382
00383 if (e) throw Error(e);
00384
00385 return Message(new Message::Private(reply), false);
00386 }
00387
00388 PendingCall Connection::send_async(Message &msg, int timeout)
00389 {
00390 DBusPendingCall *pending;
00391
00392 if (!dbus_connection_send_with_reply(_pvt->conn, msg._pvt->msg, &pending, timeout))
00393 {
00394 throw ErrorNoMemory("Unable to start asynchronous call");
00395 }
00396 return PendingCall(new PendingCall::Private(pending));
00397 }
00398
00399 void Connection::request_name(const char *name, int flags)
00400 {
00401 InternalError e;
00402
00403 debug_log("%s: registering bus name %s", unique_name(), name);
00404
00405
00406
00407
00408
00409
00410 int ret = dbus_bus_request_name(_pvt->conn, name, flags, e);
00411
00412 if (ret == -1)
00413 {
00414 if (e) throw Error(e);
00415 }
00416
00417
00418
00419 if (name)
00420 {
00421 _pvt->names.push_back(name);
00422 std::string match = "destination='" + _pvt->names.back() + "'";
00423 add_match(match.c_str());
00424 }
00425 }
00426
00427 unsigned long Connection::sender_unix_uid(const char *sender)
00428 {
00429 InternalError e;
00430
00431 unsigned long ul = dbus_bus_get_unix_user(_pvt->conn, sender, e);
00432
00433 if (e) throw Error(e);
00434
00435 return ul;
00436 }
00437
00438 bool Connection::has_name(const char *name)
00439 {
00440 InternalError e;
00441
00442 bool b = dbus_bus_name_has_owner(_pvt->conn, name, e);
00443
00444 if (e) throw Error(e);
00445
00446 return b;
00447 }
00448
00449 const std::vector<std::string>& Connection::names()
00450 {
00451 return _pvt->names;
00452 }
00453
00454 bool Connection::start_service(const char *name, unsigned long flags)
00455 {
00456 InternalError e;
00457
00458 bool b = dbus_bus_start_service_by_name(_pvt->conn, name, flags, NULL, e);
00459
00460 if (e) throw Error(e);
00461
00462 return b;
00463 }
00464
00465 void Connection::set_timeout(int timeout)
00466 {
00467 _timeout = timeout;
00468 }
00469
00470 int Connection::get_timeout()
00471 {
00472 return _timeout;
00473 }
00474