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 } 00097 00098 void Connection::Private::detach_server() 00099 { 00100 /* Server::Private *tmp = server; 00101 00102 server = NULL; 00103 00104 if (tmp) 00105 { 00106 ConnectionList::iterator i; 00107 00108 for (i = tmp->connections.begin(); i != tmp->connections.end(); ++i) 00109 { 00110 if (i->_pvt.get() == this) 00111 { 00112 tmp->connections.erase(i); 00113 break; 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: //uh oh... 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 // dbus_connection_disconnect(_pvt->conn); // disappeared in 0.9x 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 * TODO: 00407 * Think about giving back the 'ret' value. Some people on the list 00408 * requested about this... 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 // this->remove_match("destination"); 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