root/trunk/libffado/external/dbus/src/object.cpp

Revision 562, 7.8 kB (checked in by ppalmers, 17 years ago)

- add DBUS C++ bindings from:

http://dev.openwengo.org/svn/openwengo/wengophone-ng/branches/wengophone-dbus-api/libs/dbus

- statically linked because these are not released separately and

because C++ libs can (apparently) have ABI issues.

Line 
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
25 #include <dbus-c++/debug.h>
26 #include <dbus-c++/object.h>
27 #include "internalerror.h"
28
29 #include <map>
30 #include <dbus/dbus.h>
31
32 #include "message_p.h"
33 #include "server_p.h"
34 #include "connection_p.h"
35
36 using namespace DBus;
37
38 Object::Object( Connection& conn, const Path& path, const char* service )
39 :       _conn(conn), _path(path), _service(service ? service : "")
40 {
41 }
42
43 Object::~Object()
44 {
45 }
46
47 struct ObjectAdaptor::Private
48 {
49         static void unregister_function_stub( DBusConnection*, void* );
50         static DBusHandlerResult message_function_stub( DBusConnection*, DBusMessage*, void* );
51 };
52
53 static DBusObjectPathVTable _vtable =
54 {       
55         ObjectAdaptor::Private::unregister_function_stub,
56         ObjectAdaptor::Private::message_function_stub,
57         NULL, NULL, NULL, NULL
58 };
59
60 void ObjectAdaptor::Private::unregister_function_stub( DBusConnection* conn, void* data )
61 {
62         //TODO: what do we have to do here ?
63 }
64
65 DBusHandlerResult ObjectAdaptor::Private::message_function_stub( DBusConnection*, DBusMessage* dmsg, void* data )
66 {
67         ObjectAdaptor* o = static_cast<ObjectAdaptor*>(data);
68
69         if( o )
70         {
71                 Message msg(new Message::Private(dmsg));       
72
73                 debug_log("in object %s", o->path().c_str());
74                 debug_log(" got message #%d from %s to %s",
75                         msg.serial(),
76                         msg.sender(),
77                         msg.destination()
78                 );
79
80                 return o->handle_message(msg)
81                         ? DBUS_HANDLER_RESULT_HANDLED
82                         : DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
83         }
84         else
85         {
86                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
87         }
88 }
89
90 typedef std::map<Path, ObjectAdaptor*> ObjectAdaptorTable;
91 static ObjectAdaptorTable _adaptor_table;
92
93 ObjectAdaptor* ObjectAdaptor::from_path( const Path& path )
94 {
95         ObjectAdaptorTable::iterator ati = _adaptor_table.find(path);
96
97         if(ati != _adaptor_table.end())
98                 return ati->second;
99
100         return NULL;
101 }
102
103 ObjectAdaptorPList ObjectAdaptor::from_path_prefix( const std::string& prefix )
104 {
105         ObjectAdaptorPList ali;
106
107         ObjectAdaptorTable::iterator ati = _adaptor_table.begin();
108
109         size_t plen = prefix.length();
110
111         while(ati != _adaptor_table.end())
112         {
113                 if(!strncmp(ati->second->path().c_str(), prefix.c_str(), plen))
114                         ali.push_back(ati->second);
115
116                 ++ati;
117         }
118
119         return ali;
120 }
121
122 ObjectAdaptor::ObjectAdaptor( Connection& conn, const Path& path )
123 :       Object(conn, path, conn.unique_name())
124 {
125         register_obj();
126 }
127
128 ObjectAdaptor::~ObjectAdaptor()
129 {
130         unregister_obj();
131 }
132
133 void ObjectAdaptor::register_obj()
134 {
135         debug_log("registering local object %s", path().c_str());
136
137         if(!dbus_connection_register_object_path(conn()._pvt->conn, path().c_str(), &_vtable, this))
138         {
139                 throw ErrorNoMemory("unable to register object path");
140         }
141         else
142         {
143                 InterfaceAdaptorTable::const_iterator ii = _interfaces.begin();
144                 while( ii != _interfaces.end() )
145                 {
146                         std::string im = "type='method_call',interface='"+ii->first+"',path='"+path()+"'";
147                         conn().add_match(im.c_str());
148                         ++ii;
149                 }
150         }
151
152         _adaptor_table[path()] = this;
153 }
154
155 void ObjectAdaptor::unregister_obj()
156 {
157         _adaptor_table.erase(path());
158
159         debug_log("unregistering local object %s", path().c_str());
160
161         dbus_connection_unregister_object_path(conn()._pvt->conn, path().c_str());
162
163         InterfaceAdaptorTable::const_iterator ii = _interfaces.begin();
164         while( ii != _interfaces.end() )
165         {
166                 std::string im = "type='method_call',interface='"+ii->first+"',path='"+path()+"'";
167                 conn().remove_match(im.c_str());
168                 ++ii;
169         }
170 }
171
172 void ObjectAdaptor::_emit_signal( SignalMessage& sig )
173 {
174         sig.path(path().c_str());
175
176         conn().send(sig);
177 }
178
179 struct ReturnLaterError
180 {
181         const Tag* tag;
182 };
183
184 bool ObjectAdaptor::handle_message( const Message& msg )
185 {
186         switch( msg.type() )
187         {
188                 case DBUS_MESSAGE_TYPE_METHOD_CALL:
189                 {
190                         const CallMessage& cmsg = reinterpret_cast<const CallMessage&>(msg);
191                         const char* member      = cmsg.member();
192                         const char* interface   = cmsg.interface();
193
194                         debug_log(" invoking method %s.%s", interface, member);
195                
196                         InterfaceAdaptor* ii = find_interface(interface);
197                         if( ii )
198                         {
199                                 try
200                                 {
201                                         Message ret = ii->dispatch_method(cmsg);
202                                         conn().send(ret);
203                                 }
204                                 catch(Error& e)
205                                 {
206                                         ErrorMessage em(cmsg, e.name(), e.message());
207                                         conn().send(em);
208                                 }
209                                 catch(ReturnLaterError& rle)
210                                 {
211                                         _continuations[rle.tag] = new Continuation(conn(), cmsg, rle.tag);
212                                 }
213                                 return true;
214                         }
215                         else
216                         {
217                                 return false;
218                         }
219                 }
220                 default:
221                 {
222                         return false;
223                 }
224         }
225 }
226
227 void ObjectAdaptor::return_later( const Tag* tag )
228 {
229         ReturnLaterError rle = { tag };
230         throw rle;
231 }
232
233 void ObjectAdaptor::return_now( Continuation* ret )
234 {
235         ret->_conn.send(ret->_return);
236
237         ContinuationMap::iterator di = _continuations.find(ret->_tag);
238
239         delete di->second;
240
241         _continuations.erase(di);
242 }
243
244 void ObjectAdaptor::return_error( Continuation* ret, const Error error )
245 {
246         ret->_conn.send(ErrorMessage(ret->_call, error.name(), error.message()));
247
248         ContinuationMap::iterator di = _continuations.find(ret->_tag);
249
250         delete di->second;
251
252         _continuations.erase(di);
253 }
254
255 ObjectAdaptor::Continuation* ObjectAdaptor::find_continuation( const Tag* tag )
256 {
257         ContinuationMap::iterator di = _continuations.find(tag);
258
259         return di != _continuations.end() ? di->second : NULL;
260 }
261
262 ObjectAdaptor::Continuation::Continuation( Connection& conn, const CallMessage& call, const Tag* tag )
263 : _conn(conn), _call(call), _return(_call), _tag(tag)
264 {
265         _writer = _return.writer(); //todo: verify
266 }
267
268 /*
269 */
270
271 ObjectProxy::ObjectProxy( Connection& conn, const Path& path, const char* service )
272 :       Object(conn, path, service)
273 {
274         register_obj();
275 }
276
277 ObjectProxy::~ObjectProxy()
278 {
279         unregister_obj();
280 }
281
282 void ObjectProxy::register_obj()
283 {
284         debug_log("registering remote object %s", path().c_str());
285
286         _filtered = new Callback<ObjectProxy, bool, const Message&>(this, &ObjectProxy::handle_message);
287        
288         conn().add_filter(_filtered);
289
290         InterfaceProxyTable::const_iterator ii = _interfaces.begin();
291         while( ii != _interfaces.end() )
292         {
293                 std::string im = "type='signal',interface='"+ii->first+"',path='"+path()+"'";
294                 conn().add_match(im.c_str());
295                 ++ii;
296         }
297 }
298
299 void ObjectProxy::unregister_obj()
300 {
301         debug_log("unregistering remote object %s", path().c_str());
302        
303         InterfaceProxyTable::const_iterator ii = _interfaces.begin();
304         while( ii != _interfaces.end() )
305         {
306                 std::string im = "type='signal',interface='"+ii->first+"',path='"+path()+"'";
307                 conn().remove_match(im.c_str());
308                 ++ii;
309         }
310         conn().remove_filter(_filtered);
311 }
312
313 Message ObjectProxy::_invoke_method( CallMessage& call )
314 {
315         call.path(path().c_str());
316         call.destination(service().c_str());
317
318         return conn().send_blocking(call, 2000);
319 }
320
321 bool ObjectProxy::handle_message( const Message& msg )
322 {
323         switch( msg.type() )
324         {
325                 case DBUS_MESSAGE_TYPE_SIGNAL:
326                 {
327                         const SignalMessage& smsg = reinterpret_cast<const SignalMessage&>(msg);
328                         const char* interface   = smsg.interface();
329                         const char* member      = smsg.member();
330                         const char* objpath     = smsg.path();
331
332                         if( objpath != path() ) return false;
333
334                         debug_log("filtered signal %s(in %s) from %s to object %s",
335                                 member, interface, msg.sender(), objpath);
336
337                         InterfaceProxy* ii = find_interface(interface);
338                         if( ii )
339                         {
340                                 return ii->dispatch_signal(smsg);
341                         }
342                         else
343                         {
344                                 return false;
345                         }
346                 }
347                 default:
348                 {
349                         return false;
350                 }
351         }
352 }
Note: See TracBrowser for help on using the browser.