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