connection.cpp
Go to the documentation of this file.
00001 /* 00002 * 00003 * D-Bus++ - C++ bindings for D-Bus 00004 * 00005 * Copyright (C) 2005-2007 Paolo Durante <shackan@gmail.com> 00006 * 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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); //todo: the library has to own another reference 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); // TODO: some assert at least 00093 00094 dbus_connection_set_dispatch_status_function(conn, dispatch_status_stub, this, 0); 00095 dbus_connection_set_exit_on_disconnect(conn, false); //why was this set to true?? 00096 dbus_connection_set_unix_user_function (conn, 0, 0, 0); 00097 } 00098 00099 void Connection::Private::detach_server() 00100 { 00101 /* Server::Private *tmp = server; 00102 00103 server = NULL; 00104 00105 if (tmp) 00106 { 00107 ConnectionList::iterator i; 00108 00109 for (i = tmp->connections.begin(); i != tmp->connections.end(); ++i) 00110 { 00111 if (i->_pvt.get() == this) 00112 { 00113 tmp->connections.erase(i); 00114 break; 00115 } 00116 } 00117 }*/ 00118 } 00119 00120 bool Connection::Private::do_dispatch() 00121 { 00122 debug_log("dispatching on %p", conn); 00123 00124 if (!dbus_connection_get_is_connected(conn)) 00125 { 00126 debug_log("connection terminated"); 00127 00128 detach_server(); 00129 00130 return true; 00131 } 00132 00133 return dbus_connection_dispatch(conn) != DBUS_DISPATCH_DATA_REMAINS; 00134 } 00135 00136 void Connection::Private::dispatch_status_stub(DBusConnection *dc, DBusDispatchStatus status, void *data) 00137 { 00138 Private *p = static_cast<Private *>(data); 00139 00140 switch (status) 00141 { 00142 case DBUS_DISPATCH_DATA_REMAINS: 00143 debug_log("some dispatching to do on %p", dc); 00144 p->dispatcher->queue_connection(p); 00145 break; 00146 00147 case DBUS_DISPATCH_COMPLETE: 00148 debug_log("all dispatching done on %p", dc); 00149 break; 00150 00151 case DBUS_DISPATCH_NEED_MEMORY: //uh oh... 00152 debug_log("connection %p needs memory", dc); 00153 break; 00154 } 00155 } 00156 00157 DBusHandlerResult Connection::Private::message_filter_stub(DBusConnection *conn, DBusMessage *dmsg, void *data) 00158 { 00159 MessageSlot *slot = static_cast<MessageSlot *>(data); 00160 00161 Message msg = Message(new Message::Private(dmsg)); 00162 00163 return slot && !slot->empty() && slot->call(msg) 00164 ? DBUS_HANDLER_RESULT_HANDLED 00165 : DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 00166 } 00167 00168 bool Connection::Private::disconn_filter_function(const Message &msg) 00169 { 00170 if (msg.is_signal(DBUS_INTERFACE_LOCAL, "Disconnected")) 00171 { 00172 debug_log("%p disconnected by local bus", conn); 00173 dbus_connection_close(conn); 00174 00175 return true; 00176 } 00177 return false; 00178 } 00179 00180 DBusDispatchStatus Connection::Private::dispatch_status() 00181 { 00182 return dbus_connection_get_dispatch_status(conn); 00183 } 00184 00185 bool Connection::Private::has_something_to_dispatch() 00186 { 00187 return dispatch_status() == DBUS_DISPATCH_DATA_REMAINS; 00188 } 00189 00190 00191 Connection Connection::SystemBus() 00192 { 00193 return Connection(new Private(DBUS_BUS_SYSTEM)); 00194 } 00195 00196 Connection Connection::SessionBus() 00197 { 00198 return Connection(new Private(DBUS_BUS_SESSION)); 00199 } 00200 00201 Connection Connection::ActivationBus() 00202 { 00203 return Connection(new Private(DBUS_BUS_STARTER)); 00204 } 00205 00206 Connection::Connection(const char *address, bool priv) 00207 : _timeout(-1) 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), _timeout(-1) 00225 { 00226 setup(default_dispatcher); 00227 } 00228 00229 Connection::Connection(const Connection &c) 00230 : _pvt(c._pvt), _timeout(c._timeout) 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 // dbus_connection_disconnect(_pvt->conn); // disappeared in 0.9x 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 bool throw_on_error) 00335 { 00336 InternalError e; 00337 00338 dbus_bus_remove_match(_pvt->conn, rule, e); 00339 00340 debug_log("%s: removed match rule %s", unique_name(), rule); 00341 00342 if (e) 00343 { 00344 if (throw_on_error) 00345 throw Error(e); 00346 else 00347 debug_log("DBus::Connection::remove_match: %s (%s).", 00348 static_cast<DBusError *>(e)->message, 00349 static_cast<DBusError *>(e)->name); 00350 } 00351 } 00352 00353 bool Connection::add_filter(MessageSlot &s) 00354 { 00355 debug_log("%s: adding filter", unique_name()); 00356 return dbus_connection_add_filter(_pvt->conn, Private::message_filter_stub, &s, NULL); 00357 } 00358 00359 void Connection::remove_filter(MessageSlot &s) 00360 { 00361 debug_log("%s: removing filter", unique_name()); 00362 dbus_connection_remove_filter(_pvt->conn, Private::message_filter_stub, &s); 00363 } 00364 00365 bool Connection::send(const Message &msg, unsigned int *serial) 00366 { 00367 return dbus_connection_send(_pvt->conn, msg._pvt->msg, serial); 00368 } 00369 00370 Message Connection::send_blocking(Message &msg, int timeout) 00371 { 00372 DBusMessage *reply; 00373 InternalError e; 00374 00375 if (this->_timeout != -1) 00376 { 00377 reply = dbus_connection_send_with_reply_and_block(_pvt->conn, msg._pvt->msg, this->_timeout, e); 00378 } 00379 else 00380 { 00381 reply = dbus_connection_send_with_reply_and_block(_pvt->conn, msg._pvt->msg, timeout, e); 00382 } 00383 00384 if (e) throw Error(e); 00385 00386 return Message(new Message::Private(reply), false); 00387 } 00388 00389 PendingCall Connection::send_async(Message &msg, int timeout) 00390 { 00391 DBusPendingCall *pending; 00392 00393 if (!dbus_connection_send_with_reply(_pvt->conn, msg._pvt->msg, &pending, timeout)) 00394 { 00395 throw ErrorNoMemory("Unable to start asynchronous call"); 00396 } 00397 return PendingCall(new PendingCall::Private(pending)); 00398 } 00399 00400 void Connection::request_name(const char *name, int flags) 00401 { 00402 InternalError e; 00403 00404 debug_log("%s: registering bus name %s", unique_name(), name); 00405 00406 /* 00407 * TODO: 00408 * Think about giving back the 'ret' value. Some people on the list 00409 * requested about this... 00410 */ 00411 int ret = dbus_bus_request_name(_pvt->conn, name, flags, e); 00412 00413 if (ret == -1) 00414 { 00415 if (e) throw Error(e); 00416 } 00417 00418 // this->remove_match("destination"); 00419 00420 if (name) 00421 { 00422 _pvt->names.push_back(name); 00423 std::string match = "destination='" + _pvt->names.back() + "'"; 00424 add_match(match.c_str()); 00425 } 00426 } 00427 00428 unsigned long Connection::sender_unix_uid(const char *sender) 00429 { 00430 InternalError e; 00431 00432 unsigned long ul = dbus_bus_get_unix_user(_pvt->conn, sender, e); 00433 00434 if (e) throw Error(e); 00435 00436 return ul; 00437 } 00438 00439 bool Connection::has_name(const char *name) 00440 { 00441 InternalError e; 00442 00443 bool b = dbus_bus_name_has_owner(_pvt->conn, name, e); 00444 00445 if (e) throw Error(e); 00446 00447 return b; 00448 } 00449 00450 const std::vector<std::string>& Connection::names() 00451 { 00452 return _pvt->names; 00453 } 00454 00455 bool Connection::start_service(const char *name, unsigned long flags) 00456 { 00457 InternalError e; 00458 00459 bool b = dbus_bus_start_service_by_name(_pvt->conn, name, flags, NULL, e); 00460 00461 if (e) throw Error(e); 00462 00463 return b; 00464 } 00465 00466 void Connection::set_timeout(int timeout) 00467 { 00468 _timeout = timeout; 00469 } 00470 00471 int Connection::get_timeout() 00472 { 00473 return _timeout; 00474 } 00475