* rework of buildsystem
[profile/ivi/audiomanager.git] / AudioManagerDaemon / src / DBusWrapper.cpp
1 /**
2 * Copyright (C) 2011, BMW AG
3 *
4 * GeniviAudioMananger AudioManagerDaemon
5 *
6 * \file SocketHandler.cpp
7 *
8 * \date 20-Oct-2011 3:42:04 PM
9 * \author Christian Mueller (christian.ei.mueller@bmw.de)
10 *
11 * \section License
12 * GNU Lesser General Public License, version 2.1, with special exception (GENIVI clause)
13 * Copyright (C) 2011, BMW AG Christian Mueller  Christian.ei.mueller@bmw.de
14 *
15 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 2.1, as published by the Free Software Foundation.
16 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License, version 2.1, for more details.
17 * You should have received a copy of the GNU Lesser General Public License, version 2.1, along with this program; if not, see <http://www.gnu.org/licenses/lgpl-2.1.html>.
18 * Note that the copyright holders assume that the GNU Lesser General Public License, version 2.1, may also be applicable to programs even in cases in which the program is not a library in the technical sense.
19 * Linking AudioManager statically or dynamically with other modules is making a combined work based on AudioManager. You may license such other modules under the GNU Lesser General Public License, version 2.1. If you do not want to license your linked modules under the GNU Lesser General Public License, version 2.1, you may use the program under the following exception.
20 * As a special exception, the copyright holders of AudioManager give you permission to combine AudioManager with software programs or libraries that are released under any license unless such a combination is not permitted by the license of such a software program or library. You may copy and distribute such a system following the terms of the GNU Lesser General Public License, version 2.1, including this special exception, for AudioManager and the licenses of the other code concerned.
21 * Note that people who make modified versions of AudioManager are not obligated to grant this special exception for their modified versions; it is their choice whether to do so. The GNU Lesser General Public License, version 2.1, gives permission to release a modified version without this exception; this exception also makes it possible to release a modified version which carries forward this exception.
22 *
23 */
24
25 #include <dbus/DBusWrapper.h>
26 #include <SocketHandler.h>
27 #include <config.h>
28 #include <fstream>
29 #include <sstream>
30 #include <string>
31 #include <dlt/dlt.h>
32 #include <assert.h>
33 #include <stdlib.h>
34
35 using namespace am;
36
37 DLT_IMPORT_CONTEXT(DLT_CONTEXT)
38
39 #define ROOT_INTROSPECT_XML                                                                                             \
40 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                                                               \
41 "<node>"                                                                                                                                \
42 "<interface name='orAudioManagerg.freedesktop.DBus.Introspectable'>"    \
43 "<method name='Introspect'>"                                                                                    \
44 "       <arg name='xml_data' type='s' direction='out'/>"                                        \
45 "</method>"                                                                                                                     \
46 "</interface>"                                                                                                                  \
47
48 DBusWrapper* DBusWrapper::mReference = NULL;
49
50 DBusWrapper::DBusWrapper()
51         : pDbusDispatchCallback(this,&DBusWrapper::dbusDispatchCallback),
52           pDbusFireCallback(this,&DBusWrapper::dbusFireCallback),
53           pDbusCheckCallback(this,&DBusWrapper::dbusCheckCallback),
54           pDbusTimerCallback(this,&DBusWrapper::dbusTimerCallback),
55           mDbusConnection(0),
56           mDBusError(),
57           mNodesList(),
58           mListTimerhandlePointer()
59 {
60         dbus_error_init(&mDBusError);
61     DLT_LOG(DLT_CONTEXT,DLT_LOG_INFO, DLT_STRING("DBusWrapper::DBusWrapper Opening DBus connection"));
62     mDbusConnection=dbus_bus_get(DBUS_BUS_SESSION, &mDBusError);
63     if (dbus_error_is_set(&mDBusError))
64     {
65         DLT_LOG(DLT_CONTEXT,DLT_LOG_ERROR, DLT_STRING("DBusWrapper::DBusWrapper Error while getting the DBus"));
66         dbus_error_free(&mDBusError);
67     }
68     if (NULL == mDbusConnection)
69     {
70         DLT_LOG(DLT_CONTEXT,DLT_LOG_ERROR, DLT_STRING("DBusWrapper::DBusWrapper DBus Connection is null"));
71     }
72
73     //first, we are old enought to live longer then the connection:
74     dbus_connection_set_exit_on_disconnect(mDbusConnection, FALSE);
75
76         mObjectPathVTable.message_function=DBusWrapper::cbRootIntrospection;
77         dbus_connection_register_object_path(mDbusConnection,DBUS_SERVICE_OBJECT_PATH , &mObjectPathVTable, this);
78         int ret = dbus_bus_request_name(mDbusConnection,DBUS_SERVICE_PREFIX,DBUS_NAME_FLAG_DO_NOT_QUEUE, &mDBusError);
79     if (dbus_error_is_set(&mDBusError))
80     {
81         DLT_LOG(DLT_CONTEXT,DLT_LOG_ERROR, DLT_STRING("DBusWrapper::DBusWrapper Name Error"),DLT_STRING(mDBusError.message));
82         dbus_error_free(&mDBusError);
83     }
84     if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret)
85     {
86         DLT_LOG(DLT_CONTEXT,DLT_LOG_ERROR, DLT_STRING("DBusWrapper::DBusWrapper Wrapper is not the Primary Owner"), DLT_INT(ret));
87         exit(1);
88     }
89 }
90
91 DBusWrapper::DBusWrapper(SocketHandler* socketHandler)
92         : pDbusDispatchCallback(this,&DBusWrapper::dbusDispatchCallback),
93           pDbusFireCallback(this,&DBusWrapper::dbusFireCallback),
94           pDbusCheckCallback(this,&DBusWrapper::dbusCheckCallback),
95           pDbusTimerCallback(this,&DBusWrapper::dbusTimerCallback),
96           mDbusConnection(0),
97           mDBusError(),
98           mNodesList(),
99           mListTimerhandlePointer(),
100           mSocketHandler(socketHandler)
101 {
102         assert(mSocketHandler!=0);
103
104         dbus_error_init(&mDBusError);
105     DLT_LOG(DLT_CONTEXT,DLT_LOG_INFO, DLT_STRING("DBusWrapper::DBusWrapper Opening DBus connection"));
106     mDbusConnection=dbus_bus_get(DBUS_BUS_SESSION, &mDBusError);
107     if (dbus_error_is_set(&mDBusError))
108     {
109         DLT_LOG(DLT_CONTEXT,DLT_LOG_ERROR, DLT_STRING("DBusWrapper::DBusWrapper Error while getting the DBus"));
110         dbus_error_free(&mDBusError);
111     }
112     if (NULL == mDbusConnection)
113     {
114         DLT_LOG(DLT_CONTEXT,DLT_LOG_ERROR, DLT_STRING("DBusWrapper::DBusWrapper DBus Connection is null"));
115     }
116
117     //then we need to adopt the dbus to our mainloop:
118     //first, we are old enought to live longer then the connection:
119     dbus_connection_set_exit_on_disconnect(mDbusConnection, FALSE);
120
121     //we do not need the manual dispatching, since it is not allowed to call from a different thread. So leave it uncommented:
122     //dbus_connection_set_dispatch_status_function
123
124     //add watch functions:
125     dbus_bool_t watch=dbus_connection_set_watch_functions(mDbusConnection, addWatch, removeWatch, toogleWatch , this, NULL);
126     if (!watch)
127     {
128         DLT_LOG(DLT_CONTEXT,DLT_LOG_ERROR, DLT_STRING("DBusWrapper::DBusWrapper Registering of watch functions failed"));
129     }
130
131     //add timer functions:
132     dbus_bool_t timer=dbus_connection_set_timeout_functions(mDbusConnection, addTimeout, removeTimeout, toggleTimeout, this, NULL);
133     if(!timer)
134     {
135         DLT_LOG(DLT_CONTEXT,DLT_LOG_ERROR, DLT_STRING("DBusWrapper::DBusWrapper Registering of timer functions failed"));
136     }
137
138     //register callback for Introspectio
139         mObjectPathVTable.message_function=DBusWrapper::cbRootIntrospection;
140         dbus_connection_register_object_path(mDbusConnection,DBUS_SERVICE_OBJECT_PATH , &mObjectPathVTable, this);
141         int ret = dbus_bus_request_name(mDbusConnection,DBUS_SERVICE_PREFIX,DBUS_NAME_FLAG_DO_NOT_QUEUE, &mDBusError);
142     if (dbus_error_is_set(&mDBusError))
143     {
144         DLT_LOG(DLT_CONTEXT,DLT_LOG_ERROR, DLT_STRING("DBusWrapper::DBusWrapper Name Error"),DLT_STRING(mDBusError.message));
145         dbus_error_free(&mDBusError);
146     }
147     if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret)
148     {
149         DLT_LOG(DLT_CONTEXT,DLT_LOG_ERROR, DLT_STRING("DBusWrapper::DBusWrapper Wrapper is not the Primary Owner"), DLT_INT(ret));
150         exit(1);
151     }
152 }
153
154 DBusWrapper::~DBusWrapper()
155 {
156         //close the connection again
157         DLT_LOG(DLT_CONTEXT,DLT_LOG_INFO, DLT_STRING("DBusWrapper::~DBusWrapper Closing DBus connection"));
158         dbus_connection_unref(mDbusConnection);
159
160         //clean up all timerhandles we created but did not delete before
161         std::vector<sh_timerHandle_t*>::iterator it=mListTimerhandlePointer.begin();
162         for(;it!=mListTimerhandlePointer.end();++it)
163         {
164                 delete *it;
165         }
166 }
167
168 void DBusWrapper::registerCallback(const DBusObjectPathVTable* vtable, const std::string& path, void* userdata)
169 {
170         DLT_LOG(DLT_CONTEXT,DLT_LOG_INFO, DLT_STRING("DBusWrapper::~registerCallback register callback:"),DLT_STRING(path.c_str()));
171
172         std::string completePath=std::string(DBUS_SERVICE_OBJECT_PATH)+"/"+path;
173         dbus_error_init(&mDBusError);
174         mDbusConnection=dbus_bus_get(DBUS_BUS_SESSION, &mDBusError);
175         dbus_connection_register_object_path(mDbusConnection,completePath.c_str(), vtable, userdata);
176     if (dbus_error_is_set(&mDBusError))
177     {
178         DLT_LOG(DLT_CONTEXT,DLT_LOG_ERROR, DLT_STRING("DBusWrapper::registerCallack error: "),DLT_STRING(mDBusError.message));
179         dbus_error_free(&mDBusError);
180     }
181         mNodesList.push_back(path);
182 }
183
184 DBusHandlerResult DBusWrapper::cbRootIntrospection(DBusConnection *conn, DBusMessage *msg, void *reference)
185 {
186         DLT_LOG(DLT_CONTEXT,DLT_LOG_INFO, DLT_STRING("DBusWrapper::~cbRootIntrospection called:"));
187
188         mReference=(DBusWrapper*)reference;
189         std::list<std::string>nodesList=mReference->mNodesList;
190         DBusMessage * reply;
191     DBusMessageIter args;
192     dbus_uint32_t serial = 0;
193         if (dbus_message_is_method_call(msg, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
194         {
195                 std::list<std::string>::iterator nodeIter=nodesList.begin();
196                 const char *xml=ROOT_INTROSPECT_XML;
197                 std::stringstream introspect;
198                 introspect << std::string(xml);
199                 for(;nodeIter!=nodesList.end();++nodeIter)
200                 {
201                         introspect<<"<node name='"<<nodeIter->c_str()<<"'/>";
202                 }
203                 introspect<<"</node>";
204
205                 reply = dbus_message_new_method_return(msg);
206             std::string s = introspect.str();
207             const char* string=s.c_str();
208
209             // add the arguments to the reply
210             dbus_message_iter_init_append(reply, &args);
211             if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &string))
212             {
213                 DLT_LOG(DLT_CONTEXT,DLT_LOG_ERROR, DLT_STRING("DBusWrapper::~cbRootIntrospection DBUS Out Of Memory!"));
214             }
215
216             // send the reply && flush the connection
217             if (!dbus_connection_send(conn, reply, &serial))
218             {
219                 DLT_LOG(DLT_CONTEXT,DLT_LOG_ERROR, DLT_STRING("DBusWrapper::~cbRootIntrospection DBUS Out Of Memory!"));
220             }
221             dbus_connection_flush(conn);
222             // free the reply
223             dbus_message_unref(reply);
224
225                 return DBUS_HANDLER_RESULT_HANDLED;
226         }
227         else
228         {
229                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
230         }
231 }
232
233 void DBusWrapper::dbusMainLoop()
234 {
235         DLT_LOG(DLT_CONTEXT,DLT_LOG_INFO, DLT_STRING("DBusWrapper::dbusMainLoop Entering MainLoop"));
236
237         while (dbus_connection_read_write_dispatch(mDbusConnection, -1))
238         {
239
240         }
241 }
242
243 void DBusWrapper::getDBusConnection(DBusConnection *& connection) const
244 {
245         connection=mDbusConnection;
246 }
247
248 dbus_bool_t DBusWrapper::addWatch(DBusWatch *watch, void *userData)
249 {
250         mReference=(DBusWrapper*)userData;
251         assert(mReference!=0);
252         return mReference->addWatchDelegate(watch,userData);
253 }
254
255 dbus_bool_t DBusWrapper::addWatchDelegate(DBusWatch * watch, void* userData)
256 {
257         int16_t event=0;
258     sh_pollHandle_t handle=0;
259         uint flags=dbus_watch_get_flags(watch);
260
261         /* no watch flags for disabled watches */
262     if (dbus_watch_get_enabled(watch))
263     {
264         if (flags & DBUS_WATCH_READABLE) event |= POLLIN;
265         if (flags & DBUS_WATCH_WRITABLE) event |= POLLOUT;
266     }
267
268     DLT_LOG(DLT_CONTEXT,DLT_LOG_INFO, DLT_STRING("DBusWrapper::addWatchDelegate entered new watch, fd="),DLT_INT(dbus_watch_get_unix_fd(watch)),DLT_STRING("event flag="),DLT_INT(event));
269     am_Error_e error=mSocketHandler->addFDPoll(dbus_watch_get_unix_fd(watch),event,NULL,&pDbusFireCallback,&pDbusCheckCallback,&pDbusDispatchCallback,watch,handle);
270
271         //if everything is alright, add the watch and the handle to our map so we know this relationship
272         if (error==E_OK && handle!=0)
273         {
274                 mMapHandleWatch.insert(std::make_pair(watch,handle));
275                 return true;
276         }
277         DLT_LOG(DLT_CONTEXT,DLT_LOG_ERROR, DLT_STRING("DBusWrapper::addWatchDelegate entering watch failed"));
278 }
279
280 void DBusWrapper::removeWatch(DBusWatch *watch, void *userData)
281 {
282         mReference=(DBusWrapper*)userData;
283         assert(mReference!=0);
284         mReference->removeWatchDelegate(watch,userData);
285 }
286
287 void DBusWrapper::removeWatchDelegate(DBusWatch *watch, void *userData)
288 {
289         std::map<DBusWatch*,sh_pollHandle_t>::iterator iterator=mMapHandleWatch.begin();
290         iterator=mMapHandleWatch.find(watch);
291         if (iterator!=mMapHandleWatch.end()) mSocketHandler->removeFDPoll(iterator->second);
292         DLT_LOG(DLT_CONTEXT,DLT_LOG_INFO, DLT_STRING("DBusWrapper::removeWatch removed watch with handle"),DLT_INT(iterator->second));
293         mMapHandleWatch.erase(iterator);
294 }
295
296 void DBusWrapper::toogleWatch(DBusWatch *watch, void *userData)
297 {
298         mReference=(DBusWrapper*)userData;
299         assert(mReference!=0);
300         mReference->toogleWatchDelegate(watch,userData);
301 }
302
303 void DBusWrapper::toogleWatchDelegate(DBusWatch *watch, void *userData)
304 {
305         int16_t event=0;
306         int watchFD=dbus_watch_get_unix_fd(watch);
307         uint flags=dbus_watch_get_flags(watch);
308         /* no watch flags for disabled watches */
309         if (dbus_watch_get_enabled(watch))
310         {
311                 if (flags & DBUS_WATCH_READABLE) event |= POLLIN;
312                 if (flags & DBUS_WATCH_WRITABLE) event |= POLLOUT;
313         }
314         std::map<DBusWatch*,sh_pollHandle_t>::iterator iterator=mMapHandleWatch.begin();
315         iterator=mMapHandleWatch.find(watch);
316         if (iterator!=mMapHandleWatch.end()) mSocketHandler->updateEventFlags(iterator->second,event);
317         DLT_LOG(DLT_CONTEXT,DLT_LOG_INFO, DLT_STRING("DBusWrapper::toogleWatchDelegate watch was toggeled"));
318 }
319
320 dbus_bool_t DBusWrapper::addTimeout(DBusTimeout *timeout, void* userData)
321 {
322         mReference=(DBusWrapper*)userData;
323         assert(mReference!=0);
324         return mReference->addTimeoutDelegate(timeout,userData);
325 }
326
327 dbus_bool_t DBusWrapper::addTimeoutDelegate(DBusTimeout *timeout,void* userData)
328 {
329     if (!dbus_timeout_get_enabled(timeout)) return false;
330
331     //calculate the timeout in timeval
332     timespec pollTimeout;
333     int localTimeout=dbus_timeout_get_interval(timeout);
334     pollTimeout.tv_sec=localTimeout/1000;
335     pollTimeout.tv_nsec=(localTimeout%1000)*1000000;
336
337     //prepare handle and callback. new is eval, but there is no other choice because we need the pointer!
338     sh_timerHandle_t* handle=new sh_timerHandle_t;
339     mListTimerhandlePointer.push_back(handle);
340     shTimerCallBack* buffer=&pDbusTimerCallback;
341
342     //add the timer to the pollLoop
343     mSocketHandler->addTimer(pollTimeout,buffer,*handle,timeout);
344
345     //save the handle with dbus context
346     dbus_timeout_set_data(timeout, handle, NULL);
347
348     //save timeout in Socket context
349     userData=timeout;
350         DLT_LOG(DLT_CONTEXT,DLT_LOG_INFO, DLT_STRING("DBusWrapper::addTimeoutDelegate a timeout was added"));
351     return true;
352 }
353
354 void DBusWrapper::removeTimeout(DBusTimeout *timeout, void* userData)
355 {
356         mReference=(DBusWrapper*)userData;
357         assert(mReference!=0);
358         mReference->removeTimeoutDelegate(timeout,userData);
359 }
360
361 void DBusWrapper::removeTimeoutDelegate(DBusTimeout *timeout, void* userData)
362 {
363         //get the pointer to the handle and remove the timer
364         sh_timerHandle_t* handle=(sh_timerHandle_t*)dbus_timeout_get_data(timeout);
365         mSocketHandler->removeTimer(*handle);
366
367         //now go throught the timerlist and remove the pointer, free memory
368         std::vector<sh_timerHandle_t*>::iterator it=mListTimerhandlePointer.begin();
369         for(;it!=mListTimerhandlePointer.end();++it)
370         {
371                 if (*it==handle)
372                 {
373                         mListTimerhandlePointer.erase(it);
374                         break;
375                 }
376         }
377         delete handle;
378         DLT_LOG(DLT_CONTEXT,DLT_LOG_INFO, DLT_STRING("DBusWrapper::removeTimeoutDelegate a timeout was removed"));
379 }
380
381 void DBusWrapper::toggleTimeout(DBusTimeout *timeout, void* userData)
382 {
383         mReference=(DBusWrapper*)userData;
384         assert(mReference!=0);
385         mReference->toggleTimeoutDelegate(timeout,userData);
386 }
387
388 bool am::DBusWrapper::dbusDispatchCallback(const sh_pollHandle_t handle, void *userData)
389 {
390     bool returnVal=false;
391         dbus_connection_ref(mDbusConnection);
392         if (dbus_connection_dispatch(mDbusConnection)==DBUS_DISPATCH_COMPLETE) returnVal=true;
393     dbus_connection_unref(mDbusConnection);
394         DLT_LOG(DLT_CONTEXT,DLT_LOG_INFO, DLT_STRING("DBusWrapper::dbusDispatchCallback was called"));
395     return returnVal;
396 }
397
398 bool am::DBusWrapper::dbusCheckCallback(const sh_pollHandle_t handle, void *userData)
399 {
400     bool returnVal=false;
401         dbus_connection_ref(mDbusConnection);
402         if (dbus_connection_get_dispatch_status(mDbusConnection) == DBUS_DISPATCH_DATA_REMAINS) returnVal=true;
403     dbus_connection_unref(mDbusConnection);
404         DLT_LOG(DLT_CONTEXT,DLT_LOG_INFO, DLT_STRING("DBusWrapper::dbusCheckCallback was called"));
405     return returnVal;
406 }
407
408 void am::DBusWrapper::dbusFireCallback(const pollfd pollfd, const sh_pollHandle_t handle, void *userData)
409 {
410         assert(userData!=NULL);
411         uint flags=0;
412
413         if (pollfd.revents & POLLIN)    flags |= DBUS_WATCH_READABLE;
414         if (pollfd.revents & POLLOUT)   flags |= DBUS_WATCH_WRITABLE;
415         if (pollfd.revents & POLLHUP)   flags |= DBUS_WATCH_HANGUP;
416         if (pollfd.revents & POLLERR)   flags |= DBUS_WATCH_ERROR;
417
418         DBusWatch *watch=(DBusWatch*)userData;
419
420         dbus_connection_ref(mDbusConnection);
421         bool ok=dbus_watch_handle(watch, flags);
422         dbus_connection_unref(mDbusConnection);
423         DLT_LOG(DLT_CONTEXT,DLT_LOG_INFO, DLT_STRING("DBusWrapper::dbusFireCallback was called"));
424 }
425
426 void DBusWrapper::toggleTimeoutDelegate(DBusTimeout *timeout, void* userData)
427 {
428         //get the pointer to the handle and remove the timer
429         sh_timerHandle_t* handle=(sh_timerHandle_t*)dbus_timeout_get_data(timeout);
430
431         //stop or restart?
432         if (dbus_timeout_get_enabled(timeout))
433         {
434                 //calculate the timeout in timeval
435             timespec pollTimeout;
436             int localTimeout=dbus_timeout_get_interval(timeout);
437             pollTimeout.tv_sec=localTimeout/1000;
438             pollTimeout.tv_nsec=(localTimeout%1000)*1000000;
439                 mSocketHandler->restartTimer(*handle,pollTimeout);
440         }
441         else
442         {
443                 mSocketHandler->stopTimer(*handle);
444         }
445         DLT_LOG(DLT_CONTEXT,DLT_LOG_INFO, DLT_STRING("DBusWrapper::toggleTimeoutDelegate was called"));
446 }
447
448 void DBusWrapper::dbusTimerCallback(sh_timerHandle_t handle, void *userData)
449 {
450         assert(userData!=NULL);
451         if (dbus_timeout_get_enabled((DBusTimeout*)userData))
452         {
453                 timespec ts;
454                 ts.tv_nsec=-1;
455                 ts.tv_sec=-1;
456                 mSocketHandler->restartTimer(handle,ts);
457         }
458         dbus_timeout_handle((DBusTimeout*)userData);
459         DLT_LOG(DLT_CONTEXT,DLT_LOG_INFO, DLT_STRING("DBusWrapper::dbusTimerCallback was called"));
460 }
461
462
463
464
465
466
467
468
469
470
471
472