object.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++/object.h>
00030 #include "internalerror.h"
00031 
00032 #include <cstring>
00033 #include <map>
00034 #include <dbus/dbus.h>
00035 
00036 #include "message_p.h"
00037 #include "server_p.h"
00038 #include "connection_p.h"
00039 
00040 using namespace DBus;
00041 
00042 Object::Object(Connection &conn, const Path &path, const char *service)
00043   : _conn(conn), _path(path), _service(service ? service : ""), _default_timeout(-1)
00044 {
00045 }
00046 
00047 Object::~Object()
00048 {
00049 }
00050 
00051 void Object::set_timeout(int new_timeout)
00052 {
00053   debug_log("%s: %d millies", __PRETTY_FUNCTION__, new_timeout);
00054   if (new_timeout < 0 && new_timeout != -1)
00055     throw ErrorInvalidArgs("Bad timeout, cannot set it");
00056   _default_timeout = new_timeout;
00057 }
00058 
00059 struct ObjectAdaptor::Private
00060 {
00061   static void unregister_function_stub(DBusConnection *, void *);
00062   static DBusHandlerResult message_function_stub(DBusConnection *, DBusMessage *, void *);
00063 };
00064 
00065 static DBusObjectPathVTable _vtable =
00066 {
00067   ObjectAdaptor::Private::unregister_function_stub,
00068   ObjectAdaptor::Private::message_function_stub,
00069   NULL, NULL, NULL, NULL
00070 };
00071 
00072 void ObjectAdaptor::Private::unregister_function_stub(DBusConnection *conn, void *data)
00073 {
00074   //TODO: what do we have to do here ?
00075 }
00076 
00077 DBusHandlerResult ObjectAdaptor::Private::message_function_stub(DBusConnection *, DBusMessage *dmsg, void *data)
00078 {
00079   ObjectAdaptor *o = static_cast<ObjectAdaptor *>(data);
00080 
00081   if (o)
00082   {
00083     Message msg(new Message::Private(dmsg));
00084 
00085     debug_log("in object %s", o->path().c_str());
00086     debug_log(" got message #%d from %s to %s",
00087               msg.serial(),
00088               msg.sender(),
00089               msg.destination()
00090              );
00091 
00092     return o->handle_message(msg)
00093            ? DBUS_HANDLER_RESULT_HANDLED
00094            : DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00095   }
00096   else
00097   {
00098     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00099   }
00100 }
00101 
00102 typedef std::map<Path, ObjectAdaptor *> ObjectAdaptorTable;
00103 static ObjectAdaptorTable _adaptor_table;
00104 
00105 ObjectAdaptor *ObjectAdaptor::from_path(const Path &path)
00106 {
00107   ObjectAdaptorTable::iterator ati = _adaptor_table.find(path);
00108 
00109   if (ati != _adaptor_table.end())
00110     return ati->second;
00111 
00112   return NULL;
00113 }
00114 
00115 ObjectAdaptorPList ObjectAdaptor::from_path_prefix(const std::string &prefix)
00116 {
00117   ObjectAdaptorPList ali;
00118 
00119   ObjectAdaptorTable::iterator ati = _adaptor_table.begin();
00120 
00121   size_t plen = prefix.length();
00122 
00123   while (ati != _adaptor_table.end())
00124   {
00125     if (!strncmp(ati->second->path().c_str(), prefix.c_str(), plen))
00126       ali.push_back(ati->second);
00127 
00128     ++ati;
00129   }
00130 
00131   return ali;
00132 }
00133 
00134 ObjectPathList ObjectAdaptor::child_nodes_from_prefix(const std::string &prefix)
00135 {
00136   ObjectPathList ali;
00137 
00138   ObjectAdaptorTable::iterator ati = _adaptor_table.begin();
00139 
00140   size_t plen = prefix.length();
00141 
00142   while (ati != _adaptor_table.end())
00143   {
00144     if (!strncmp(ati->second->path().c_str(), prefix.c_str(), plen))
00145     {
00146       std::string p = ati->second->path().substr(plen);
00147       p = p.substr(0, p.find('/'));
00148       ali.push_back(p);
00149     }
00150     ++ati;
00151   }
00152 
00153   ali.sort();
00154   ali.unique();
00155 
00156   return ali;
00157 }
00158 
00159 ObjectAdaptor::ObjectAdaptor(Connection &conn, const Path &path)
00160   : Object(conn, path, conn.unique_name())
00161 {
00162   register_obj();
00163 }
00164 
00165 ObjectAdaptor::~ObjectAdaptor()
00166 {
00167   unregister_obj(false);
00168 }
00169 
00170 void ObjectAdaptor::register_obj()
00171 {
00172   debug_log("registering local object %s", path().c_str());
00173 
00174   if (!dbus_connection_register_object_path(conn()._pvt->conn, path().c_str(), &_vtable, this))
00175   {
00176     throw ErrorNoMemory("unable to register object path");
00177   }
00178 
00179   _adaptor_table[path()] = this;
00180 }
00181 
00182 void ObjectAdaptor::unregister_obj(bool)
00183 {
00184   _adaptor_table.erase(path());
00185 
00186   debug_log("unregistering local object %s", path().c_str());
00187 
00188   dbus_connection_unregister_object_path(conn()._pvt->conn, path().c_str());
00189 }
00190 
00191 void ObjectAdaptor::_emit_signal(SignalMessage &sig)
00192 {
00193   sig.path(path().c_str());
00194 
00195   conn().send(sig);
00196 }
00197 
00198 struct ReturnLaterError
00199 {
00200   const Tag *tag;
00201 };
00202 
00203 bool ObjectAdaptor::handle_message(const Message &msg)
00204 {
00205   switch (msg.type())
00206   {
00207   case DBUS_MESSAGE_TYPE_METHOD_CALL:
00208   {
00209     const CallMessage &cmsg = reinterpret_cast<const CallMessage &>(msg);
00210     const char *member      = cmsg.member();
00211     const char *interface   = cmsg.interface();
00212 
00213     debug_log(" invoking method %s.%s", interface, member);
00214 
00215     InterfaceAdaptor *ii = find_interface(interface);
00216     if (ii)
00217     {
00218       try
00219       {
00220         Message ret = ii->dispatch_method(cmsg);
00221         conn().send(ret);
00222       }
00223       catch (Error &e)
00224       {
00225         ErrorMessage em(cmsg, e.name(), e.message());
00226         conn().send(em);
00227       }
00228       catch (ReturnLaterError &rle)
00229       {
00230         _continuations[rle.tag] = new Continuation(conn(), cmsg, rle.tag);
00231       }
00232       return true;
00233     }
00234     else
00235     {
00236       return false;
00237     }
00238   }
00239   default:
00240   {
00241     return false;
00242   }
00243   }
00244 }
00245 
00246 void ObjectAdaptor::return_later(const Tag *tag)
00247 {
00248   ReturnLaterError rle = { tag };
00249   throw rle;
00250 }
00251 
00252 void ObjectAdaptor::return_now(Continuation *ret)
00253 {
00254   ret->_conn.send(ret->_return);
00255 
00256   ContinuationMap::iterator di = _continuations.find(ret->_tag);
00257 
00258   delete di->second;
00259 
00260   _continuations.erase(di);
00261 }
00262 
00263 void ObjectAdaptor::return_error(Continuation *ret, const Error error)
00264 {
00265   ret->_conn.send(ErrorMessage(ret->_call, error.name(), error.message()));
00266 
00267   ContinuationMap::iterator di = _continuations.find(ret->_tag);
00268 
00269   delete di->second;
00270 
00271   _continuations.erase(di);
00272 }
00273 
00274 ObjectAdaptor::Continuation *ObjectAdaptor::find_continuation(const Tag *tag)
00275 {
00276   ContinuationMap::iterator di = _continuations.find(tag);
00277 
00278   return di != _continuations.end() ? di->second : NULL;
00279 }
00280 
00281 ObjectAdaptor::Continuation::Continuation(Connection &conn, const CallMessage &call, const Tag *tag)
00282   : _conn(conn), _call(call), _return(_call), _tag(tag)
00283 {
00284   _writer = _return.writer(); //todo: verify
00285 }
00286 
00287 /*
00288 */
00289 
00290 ObjectProxy::ObjectProxy(Connection &conn, const Path &path, const char *service)
00291   : Object(conn, path, service)
00292 {
00293   register_obj();
00294 }
00295 
00296 ObjectProxy::~ObjectProxy()
00297 {
00298   unregister_obj(false);
00299 }
00300 
00301 void ObjectProxy::register_obj()
00302 {
00303   debug_log("registering remote object %s", path().c_str());
00304 
00305   _filtered = new Callback<ObjectProxy, bool, const Message &>(this, &ObjectProxy::handle_message);
00306 
00307   conn().add_filter(_filtered);
00308 
00309   InterfaceProxyTable::const_iterator ii = _interfaces.begin();
00310   while (ii != _interfaces.end())
00311   {
00312     std::string im = "type='signal',interface='" + ii->first + "',path='" + path() + "'";
00313     conn().add_match(im.c_str());
00314     ++ii;
00315   }
00316 }
00317 
00318 void ObjectProxy::unregister_obj(bool throw_on_error)
00319 {
00320   debug_log("unregistering remote object %s", path().c_str());
00321 
00322   InterfaceProxyTable::const_iterator ii = _interfaces.begin();
00323   while (ii != _interfaces.end())
00324   {
00325     std::string im = "type='signal',interface='" + ii->first + "',path='" + path() + "'";
00326     conn().remove_match(im.c_str(), throw_on_error);
00327     ++ii;
00328   }
00329   conn().remove_filter(_filtered);
00330 }
00331 
00332 Message ObjectProxy::_invoke_method(CallMessage &call)
00333 {
00334   if (call.path() == NULL)
00335     call.path(path().c_str());
00336 
00337   if (call.destination() == NULL)
00338     call.destination(service().c_str());
00339 
00340   return conn().send_blocking(call, get_timeout());
00341 }
00342 
00343 bool ObjectProxy::_invoke_method_noreply(CallMessage &call)
00344 {
00345   if (call.path() == NULL)
00346     call.path(path().c_str());
00347 
00348   if (call.destination() == NULL)
00349     call.destination(service().c_str());
00350 
00351   return conn().send(call);
00352 }
00353 
00354 bool ObjectProxy::handle_message(const Message &msg)
00355 {
00356   switch (msg.type())
00357   {
00358   case DBUS_MESSAGE_TYPE_SIGNAL:
00359   {
00360     const SignalMessage &smsg = reinterpret_cast<const SignalMessage &>(msg);
00361     const char *interface = smsg.interface();
00362     const char *member  = smsg.member();
00363     const char *objpath = smsg.path();
00364 
00365     if (objpath != path()) return false;
00366 
00367     debug_log("filtered signal %s(in %s) from %s to object %s",
00368               member, interface, msg.sender(), objpath);
00369 
00370     InterfaceProxy *ii = find_interface(interface);
00371     if (ii)
00372     {
00373       return ii->dispatch_signal(smsg);
00374     }
00375     else
00376     {
00377       return false;
00378     }
00379   }
00380   default:
00381   {
00382     return false;
00383   }
00384   }
00385 }