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