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