* regenerated EA code based on Conti Feedback.
[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(AudioManager)
38
39 #define ROOT_INTROSPECT_XML                                                                                             \
40 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                                                               \
41 "<node>"                                                                                                                                \
42 "<interface name='org.AudioManager.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(AudioManager, 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(AudioManager, 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(AudioManager, 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(AudioManager, 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(AudioManager, 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(AudioManager, 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(AudioManager, 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(AudioManager, 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(AudioManager, 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(AudioManager, 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(AudioManager, 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(AudioManager, 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(AudioManager, 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(AudioManager, 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(AudioManager, 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(AudioManager, 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(AudioManager, 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(AudioManager, 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(AudioManager, 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     (void) userData;
258     int16_t event = 0;
259     sh_pollHandle_t handle = 0;
260     uint flags = dbus_watch_get_flags(watch);
261
262     /* no watch flags for disabled watches */
263     if (dbus_watch_get_enabled(watch))
264     {
265         if (flags & DBUS_WATCH_READABLE)
266             event |= POLLIN;
267         if (flags & DBUS_WATCH_WRITABLE)
268             event |= POLLOUT;
269     }
270
271     DLT_LOG(AudioManager, 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));
272     am_Error_e error = mSocketHandler->addFDPoll(dbus_watch_get_unix_fd(watch), event, NULL, &pDbusFireCallback, &pDbusCheckCallback, &pDbusDispatchCallback, watch, handle);
273
274     //if everything is alright, add the watch and the handle to our map so we know this relationship
275     if (error == E_OK && handle != 0)
276     {
277         mMapHandleWatch.insert(std::make_pair(watch, handle));
278         return true;
279     }DLT_LOG(AudioManager, DLT_LOG_ERROR, DLT_STRING("DBusWrapper::addWatchDelegate entering watch failed"));
280     return (true);
281 }
282
283 void DBusWrapper::removeWatch(DBusWatch *watch, void *userData)
284 {
285     mReference = (DBusWrapper*) userData;
286     assert(mReference!=0);
287     mReference->removeWatchDelegate(watch, userData);
288 }
289
290 void DBusWrapper::removeWatchDelegate(DBusWatch *watch, void *userData)
291 {
292     (void) userData;
293     std::map<DBusWatch*, sh_pollHandle_t>::iterator iterator = mMapHandleWatch.begin();
294     iterator = mMapHandleWatch.find(watch);
295     if (iterator != mMapHandleWatch.end())
296         mSocketHandler->removeFDPoll(iterator->second);
297     DLT_LOG(AudioManager, DLT_LOG_INFO, DLT_STRING("DBusWrapper::removeWatch removed watch with handle"), DLT_INT(iterator->second));
298     mMapHandleWatch.erase(iterator);
299 }
300
301 void DBusWrapper::toogleWatch(DBusWatch *watch, void *userData)
302 {
303     mReference = (DBusWrapper*) userData;
304     assert(mReference!=0);
305     mReference->toogleWatchDelegate(watch, userData);
306 }
307
308 void DBusWrapper::toogleWatchDelegate(DBusWatch *watch, void *userData)
309 {
310     (void) userData;
311     int16_t event = 0;
312     dbus_watch_get_unix_fd(watch);
313     uint flags = dbus_watch_get_flags(watch);
314     /* no watch flags for disabled watches */
315     if (dbus_watch_get_enabled(watch))
316     {
317         if (flags & DBUS_WATCH_READABLE)
318             event |= POLLIN;
319         if (flags & DBUS_WATCH_WRITABLE)
320             event |= POLLOUT;
321     }
322     std::map<DBusWatch*, sh_pollHandle_t>::iterator iterator = mMapHandleWatch.begin();
323     iterator = mMapHandleWatch.find(watch);
324     if (iterator != mMapHandleWatch.end())
325         mSocketHandler->updateEventFlags(iterator->second, event);
326     DLT_LOG(AudioManager, DLT_LOG_INFO, DLT_STRING("DBusWrapper::toogleWatchDelegate watch was toggeled"));
327 }
328
329 dbus_bool_t DBusWrapper::addTimeout(DBusTimeout *timeout, void* userData)
330 {
331     mReference = (DBusWrapper*) userData;
332     assert(mReference!=0);
333     return mReference->addTimeoutDelegate(timeout, userData);
334 }
335
336 dbus_bool_t DBusWrapper::addTimeoutDelegate(DBusTimeout *timeout, void* userData)
337 {
338     if (!dbus_timeout_get_enabled(timeout))
339         return false;
340
341     //calculate the timeout in timeval
342     timespec pollTimeout;
343     int localTimeout = dbus_timeout_get_interval(timeout);
344     pollTimeout.tv_sec = localTimeout / 1000;
345     pollTimeout.tv_nsec = (localTimeout % 1000) * 1000000;
346
347     //prepare handle and callback. new is eval, but there is no other choice because we need the pointer!
348     sh_timerHandle_t* handle = new sh_timerHandle_t;
349     mListTimerhandlePointer.push_back(handle);
350     shTimerCallBack* buffer = &pDbusTimerCallback;
351
352     //add the timer to the pollLoop
353     mSocketHandler->addTimer(pollTimeout, buffer, *handle, timeout);
354
355     //save the handle with dbus context
356     dbus_timeout_set_data(timeout, handle, NULL);
357
358     //save timeout in Socket context
359     userData = timeout;
360     DLT_LOG(AudioManager, DLT_LOG_INFO, DLT_STRING("DBusWrapper::addTimeoutDelegate a timeout was added"));
361     return true;
362 }
363
364 void DBusWrapper::removeTimeout(DBusTimeout *timeout, void* userData)
365 {
366     mReference = (DBusWrapper*) userData;
367     assert(mReference!=0);
368     mReference->removeTimeoutDelegate(timeout, userData);
369 }
370
371 void DBusWrapper::removeTimeoutDelegate(DBusTimeout *timeout, void* userData)
372 {
373     (void) userData;
374     //get the pointer to the handle and remove the timer
375     sh_timerHandle_t* handle = (sh_timerHandle_t*) dbus_timeout_get_data(timeout);
376     mSocketHandler->removeTimer(*handle);
377
378     //now go throught the timerlist and remove the pointer, free memory
379     std::vector<sh_timerHandle_t*>::iterator it = mListTimerhandlePointer.begin();
380     for (; it != mListTimerhandlePointer.end(); ++it)
381     {
382         if (*it == handle)
383         {
384             mListTimerhandlePointer.erase(it);
385             break;
386         }
387     }
388     delete handle;
389     DLT_LOG(AudioManager, DLT_LOG_INFO, DLT_STRING("DBusWrapper::removeTimeoutDelegate a timeout was removed"));
390 }
391
392 void DBusWrapper::toggleTimeout(DBusTimeout *timeout, void* userData)
393 {
394     mReference = (DBusWrapper*) userData;
395     assert(mReference!=0);
396     mReference->toggleTimeoutDelegate(timeout, userData);
397 }
398
399 bool am::DBusWrapper::dbusDispatchCallback(const sh_pollHandle_t handle, void *userData)
400 {
401     (void) handle;
402     (void) userData;
403     bool returnVal = true;
404     dbus_connection_ref(mDbusConnection);
405     if (dbus_connection_dispatch(mDbusConnection) == DBUS_DISPATCH_COMPLETE)
406         returnVal = false;
407     dbus_connection_unref(mDbusConnection);
408     DLT_LOG(AudioManager, DLT_LOG_INFO, DLT_STRING("DBusWrapper::dbusDispatchCallback was called"));
409     return returnVal;
410 }
411
412 bool am::DBusWrapper::dbusCheckCallback(const sh_pollHandle_t handle, void *userData)
413 {
414     (void) handle;
415     (void) userData;
416     bool returnVal = false;
417     dbus_connection_ref(mDbusConnection);
418     if (dbus_connection_get_dispatch_status(mDbusConnection) == DBUS_DISPATCH_DATA_REMAINS)
419         returnVal = true;
420     dbus_connection_unref(mDbusConnection);
421     DLT_LOG(AudioManager, DLT_LOG_INFO, DLT_STRING("DBusWrapper::dbusCheckCallback was called"));
422     return returnVal;
423 }
424
425 void am::DBusWrapper::dbusFireCallback(const pollfd pollfd, const sh_pollHandle_t handle, void *userData)
426 {
427     (void) handle;
428     (void) userData;
429     assert(userData!=NULL);
430     uint flags = 0;
431
432     if (pollfd.revents & POLLIN)
433         flags |= DBUS_WATCH_READABLE;
434     if (pollfd.revents & POLLOUT)
435         flags |= DBUS_WATCH_WRITABLE;
436     if (pollfd.revents & POLLHUP)
437         flags |= DBUS_WATCH_HANGUP;
438     if (pollfd.revents & POLLERR)
439         flags |= DBUS_WATCH_ERROR;
440
441     DBusWatch *watch = (DBusWatch*) userData;
442
443     dbus_connection_ref(mDbusConnection);
444     dbus_watch_handle(watch, flags);
445     dbus_connection_unref(mDbusConnection);
446     DLT_LOG(AudioManager, DLT_LOG_INFO, DLT_STRING("DBusWrapper::dbusFireCallback was called"));
447 }
448
449 void DBusWrapper::toggleTimeoutDelegate(DBusTimeout *timeout, void* userData)
450 {
451     (void) userData;
452     //get the pointer to the handle and remove the timer
453     sh_timerHandle_t* handle = (sh_timerHandle_t*) dbus_timeout_get_data(timeout);
454
455     //stop or restart?
456     if (dbus_timeout_get_enabled(timeout))
457     {
458         //calculate the timeout in timeval
459         timespec pollTimeout;
460         int localTimeout = dbus_timeout_get_interval(timeout);
461         pollTimeout.tv_sec = localTimeout / 1000;
462         pollTimeout.tv_nsec = (localTimeout % 1000) * 1000000;
463         mSocketHandler->restartTimer(*handle, pollTimeout);
464     }
465     else
466     {
467         mSocketHandler->stopTimer(*handle);
468     }DLT_LOG(AudioManager, DLT_LOG_INFO, DLT_STRING("DBusWrapper::toggleTimeoutDelegate was called"));
469 }
470
471 void DBusWrapper::dbusTimerCallback(sh_timerHandle_t handle, void *userData)
472 {
473     assert(userData!=NULL);
474     if (dbus_timeout_get_enabled((DBusTimeout*) userData))
475     {
476         timespec ts;
477         ts.tv_nsec = -1;
478         ts.tv_sec = -1;
479         mSocketHandler->restartTimer(handle, ts);
480     }
481     dbus_timeout_handle((DBusTimeout*) userData);
482     DLT_LOG(AudioManager, DLT_LOG_INFO, DLT_STRING("DBusWrapper::dbusTimerCallback was called"));
483 }
484