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 }