object.cpp
Go to the documentation of this file.
1 /*
2  *
3  * D-Bus++ - C++ bindings for D-Bus
4  *
5  * Copyright (C) 2005-2007 Paolo Durante <shackan@gmail.com>
6  *
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  *
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <dbus-c++/debug.h>
29 #include <dbus-c++/object.h>
30 #include "internalerror.h"
31 
32 #include <cstring>
33 #include <map>
34 #include <dbus/dbus.h>
35 
36 #include "message_p.h"
37 #include "server_p.h"
38 #include "connection_p.h"
39 
40 using namespace DBus;
41 
42 Object::Object(Connection &conn, const Path &path, const char *service)
43  : _conn(conn), _path(path), _service(service ? service : ""), _default_timeout(-1)
44 {
45 }
46 
48 {
49 }
50 
51 void Object::set_timeout(int new_timeout)
52 {
53  debug_log("%s: %d millies", __PRETTY_FUNCTION__, new_timeout);
54  if (new_timeout < 0 && new_timeout != -1)
55  throw ErrorInvalidArgs("Bad timeout, cannot set it");
56  _default_timeout = new_timeout;
57 }
58 
60 {
61  static void unregister_function_stub(DBusConnection *, void *);
62  static DBusHandlerResult message_function_stub(DBusConnection *, DBusMessage *, void *);
63 };
64 
65 static DBusObjectPathVTable _vtable =
66 {
69  NULL, NULL, NULL, NULL
70 };
71 
72 void ObjectAdaptor::Private::unregister_function_stub(DBusConnection *conn, void *data)
73 {
74  //TODO: what do we have to do here ?
75 }
76 
77 DBusHandlerResult ObjectAdaptor::Private::message_function_stub(DBusConnection *, DBusMessage *dmsg, void *data)
78 {
79  ObjectAdaptor *o = static_cast<ObjectAdaptor *>(data);
80 
81  if (o)
82  {
83  Message msg(new Message::Private(dmsg));
84 
85  debug_log("in object %s", o->path().c_str());
86  debug_log(" got message #%d from %s to %s",
87  msg.serial(),
88  msg.sender(),
89  msg.destination()
90  );
91 
92  return o->handle_message(msg)
93  ? DBUS_HANDLER_RESULT_HANDLED
94  : DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
95  }
96  else
97  {
98  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
99  }
100 }
101 
102 typedef std::map<Path, ObjectAdaptor *> ObjectAdaptorTable;
104 
105 ObjectAdaptor *ObjectAdaptor::from_path(const Path &path)
106 {
107  ObjectAdaptorTable::iterator ati = _adaptor_table.find(path);
108 
109  if (ati != _adaptor_table.end())
110  return ati->second;
111 
112  return NULL;
113 }
114 
115 ObjectAdaptorPList ObjectAdaptor::from_path_prefix(const std::string &prefix)
116 {
117  ObjectAdaptorPList ali;
118 
119  ObjectAdaptorTable::iterator ati = _adaptor_table.begin();
120 
121  size_t plen = prefix.length();
122 
123  while (ati != _adaptor_table.end())
124  {
125  if (!strncmp(ati->second->path().c_str(), prefix.c_str(), plen))
126  ali.push_back(ati->second);
127 
128  ++ati;
129  }
130 
131  return ali;
132 }
133 
134 ObjectPathList ObjectAdaptor::child_nodes_from_prefix(const std::string &prefix)
135 {
136  ObjectPathList ali;
137 
138  ObjectAdaptorTable::iterator ati = _adaptor_table.begin();
139 
140  size_t plen = prefix.length();
141 
142  while (ati != _adaptor_table.end())
143  {
144  if (!strncmp(ati->second->path().c_str(), prefix.c_str(), plen))
145  {
146  std::string p = ati->second->path().substr(plen);
147  p = p.substr(0, p.find('/'));
148  ali.push_back(p);
149  }
150  ++ati;
151  }
152 
153  ali.sort();
154  ali.unique();
155 
156  return ali;
157 }
158 
159 ObjectAdaptor::ObjectAdaptor(Connection &conn, const Path &path)
160  : Object(conn, path, conn.unique_name())
161 {
162  register_obj();
163 }
164 
166 {
167  unregister_obj(false);
168 }
169 
171 {
172  debug_log("registering local object %s", path().c_str());
173 
174  if (!dbus_connection_register_object_path(conn()._pvt->conn, path().c_str(), &_vtable, this))
175  {
176  throw ErrorNoMemory("unable to register object path");
177  }
178 
179  _adaptor_table[path()] = this;
180 }
181 
183 {
184  _adaptor_table.erase(path());
185 
186  debug_log("unregistering local object %s", path().c_str());
187 
188  dbus_connection_unregister_object_path(conn()._pvt->conn, path().c_str());
189 }
190 
192 {
193  sig.path(path().c_str());
194 
195  conn().send(sig);
196 }
197 
199 {
200  const Tag *tag;
201 };
202 
204 {
205  switch (msg.type())
206  {
207  case DBUS_MESSAGE_TYPE_METHOD_CALL:
208  {
209  const CallMessage &cmsg = reinterpret_cast<const CallMessage &>(msg);
210  const char *member = cmsg.member();
211  const char *interface = cmsg.interface();
212  InterfaceAdaptor *ii = NULL;
213 
214  debug_log(" invoking method %s.%s", interface, member);
215 
216  if (interface)
217  ii = find_interface(interface);
218  else
219  ii = NULL;
220 
221  if (ii)
222  {
223  try
224  {
225  Message ret = ii->dispatch_method(cmsg);
226  conn().send(ret);
227  }
228  catch (Error &e)
229  {
230  ErrorMessage em(cmsg, e.name(), e.message());
231  conn().send(em);
232  }
233  catch (ReturnLaterError &rle)
234  {
235  _continuations[rle.tag] = new Continuation(conn(), cmsg, rle.tag);
236  }
237  return true;
238  }
239  else
240  {
241  return false;
242  }
243  }
244  default:
245  {
246  return false;
247  }
248  }
249 }
250 
252 {
253  ReturnLaterError rle = { tag };
254  throw rle;
255 }
256 
258 {
259  ret->_conn.send(ret->_return);
260 
261  ContinuationMap::iterator di = _continuations.find(ret->_tag);
262 
263  delete di->second;
264 
265  _continuations.erase(di);
266 }
267 
269 {
270  ret->_conn.send(ErrorMessage(ret->_call, error.name(), error.message()));
271 
272  ContinuationMap::iterator di = _continuations.find(ret->_tag);
273 
274  delete di->second;
275 
276  _continuations.erase(di);
277 }
278 
280 {
281  ContinuationMap::iterator di = _continuations.find(tag);
282 
283  return di != _continuations.end() ? di->second : NULL;
284 }
285 
287  : _conn(conn), _call(call), _return(_call), _tag(tag)
288 {
289  _writer = _return.writer(); //todo: verify
290 }
291 
292 /*
293 */
294 
296  : Object(conn, path, service)
297 {
298  register_obj();
299 }
300 
302 {
303  unregister_obj(false);
304 }
305 
307 {
308  debug_log("registering remote object %s", path().c_str());
309 
311 
313 
314  InterfaceProxyTable::const_iterator ii = _interfaces.begin();
315  while (ii != _interfaces.end())
316  {
317  std::string im = "type='signal',interface='" + ii->first + "',path='" + path() + "'";
318  conn().add_match(im.c_str());
319  ++ii;
320  }
321 }
322 
323 void ObjectProxy::unregister_obj(bool throw_on_error)
324 {
325  debug_log("unregistering remote object %s", path().c_str());
326 
327  InterfaceProxyTable::const_iterator ii = _interfaces.begin();
328  while (ii != _interfaces.end())
329  {
330  std::string im = "type='signal',interface='" + ii->first + "',path='" + path() + "'";
331  conn().remove_match(im.c_str(), throw_on_error);
332  ++ii;
333  }
335 }
336 
338 {
339  if (call.path() == NULL)
340  call.path(path().c_str());
341 
342  if (call.destination() == NULL)
343  call.destination(service().c_str());
344 
345  return conn().send_blocking(call, get_timeout());
346 }
347 
349 {
350  if (call.path() == NULL)
351  call.path(path().c_str());
352 
353  if (call.destination() == NULL)
354  call.destination(service().c_str());
355 
356  return conn().send(call);
357 }
358 
360 {
361  switch (msg.type())
362  {
363  case DBUS_MESSAGE_TYPE_SIGNAL:
364  {
365  const SignalMessage &smsg = reinterpret_cast<const SignalMessage &>(msg);
366  const char *interface = smsg.interface();
367  const char *member = smsg.member();
368  const char *objpath = smsg.path();
369 
370  if (objpath != path()) return false;
371 
372  debug_log("filtered signal %s(in %s) from %s to object %s",
373  member, interface, msg.sender(), objpath);
374 
375  InterfaceProxy *ii = find_interface(interface);
376  if (ii)
377  {
378  return ii->dispatch_signal(smsg);
379  }
380  else
381  {
382  return false;
383  }
384  }
385  default:
386  {
387  return false;
388  }
389  }
390 }
virtual ~Object()
Definition: object.cpp:47
bool add_filter(MessageSlot &s)
Adds a message filter.
Definition: connection.cpp:352
const char * destination() const
Definition: message.cpp:456
const char * name() const
Definition: error.cpp:65
static void unregister_function_stub(DBusConnection *, void *)
Definition: object.cpp:72
const char * path() const
Definition: message.cpp:612
void register_obj()
Definition: object.cpp:306
const char * member() const
Definition: message.cpp:547
Message send_blocking(Message &msg, int timeout=-1)
Sends a message and blocks a certain time period while waiting for a reply.
Definition: connection.cpp:369
MessageSlot _filtered
Definition: object.h:225
int get_timeout() const
Definition: object.h:92
void unregister_obj(bool throw_on_error=true)
Definition: object.cpp:323
void unregister_obj(bool throw_on_error=true)
Definition: object.cpp:182
void add_match(const char *rule)
Adds a match rule to match messages going through the message bus.
Definition: connection.cpp:321
ContinuationMap _continuations
Definition: object.h:175
const char * path() const
Definition: message.cpp:557
std::list< std::string > ObjectPathList
Definition: object.h:114
DXXAPI LogFunction debug_log
Definition: debug.cpp:55
void _emit_signal(SignalMessage &)
Definition: object.cpp:191
Message _invoke_method(CallMessage &)
Definition: object.cpp:337
void set_timeout(int new_timeout=-1)
Definition: object.cpp:51
void return_error(Continuation *ret, const Error error)
Definition: object.cpp:268
const char * member() const
Definition: message.cpp:602
static DBusHandlerResult message_function_stub(DBusConnection *, DBusMessage *, void *)
Definition: object.cpp:77
InterfaceProxy * find_interface(const std::string &name)
Definition: interface.cpp:116
bool send(const Message &msg, unsigned int *serial=NULL)
Adds a message to the outgoing message queue.
Definition: connection.cpp:364
void return_now(Continuation *ret)
Definition: object.cpp:257
const Tag * tag
Definition: object.cpp:200
void remove_filter(MessageSlot &s)
Removes a previously-added message filter.
Definition: connection.cpp:358
std::list< ObjectAdaptor * > ObjectAdaptorPList
Definition: object.h:111
const char * sender() const
Definition: message.cpp:446
InterfaceAdaptor * find_interface(const std::string &name)
Definition: interface.cpp:42
InterfaceProxyTable _interfaces
Definition: interface.h:102
bool handle_message(const Message &)
Definition: object.cpp:203
DBusConnection * conn
Definition: connection_p.h:46
bool handle_message(const Message &)
Definition: object.cpp:359
Continuation(Connection &conn, const CallMessage &call, const Tag *tag)
Definition: object.cpp:286
int serial() const
Definition: message.cpp:431
int _default_timeout
Definition: object.h:71
const DBus::Path & path() const
Definition: object.h:82
int type() const
Definition: message.cpp:426
bool _invoke_method_noreply(CallMessage &call)
Definition: object.cpp:348
const char * message() const
Definition: error.cpp:70
Object(Connection &conn, const Path &path, const char *service)
Definition: object.cpp:42
static DBusObjectPathVTable _vtable
Definition: object.cpp:65
void remove_match(const char *rule, bool throw_on_error)
Removes a previously-added match rule "by value" (the most recently-added identical rule gets removed...
Definition: connection.cpp:332
ObjectProxy(Connection &conn, const Path &path, const char *service="")
Definition: object.cpp:295
void return_later(const Tag *tag)
Definition: object.cpp:251
static ObjectAdaptorTable _adaptor_table
Definition: object.cpp:103
Connection & conn()
Definition: object.h:77
const std::string & service() const
Definition: object.h:87
Continuation * find_continuation(const Tag *tag)
Definition: object.cpp:279
MessageIter writer()
Definition: message.cpp:476
std::map< Path, ObjectAdaptor * > ObjectAdaptorTable
Definition: object.cpp:102