* [ GAM-6 ] enhace routing algorithm: changed the way the routing algorithm gets...
[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 <cassert>
32 #include <cstdlib>
33 #include "DLTWrapper.h"
34
35 using namespace am;
36
37 #define ROOT_INTROSPECT_XML                                                                                             \
38 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                                                               \
39 "<node>"                                                                                                                                \
40 "<interface name='org.AudioManager.freedesktop.DBus.Introspectable'>"   \
41 "<method name='Introspect'>"                                                                                    \
42 "       <arg name='xml_data' type='s' direction='out'/>"                                        \
43 "</method>"                                                                                                                     \
44 "</interface>"                                                                                                                  \
45
46 DBusWrapper* DBusWrapper::mReference = NULL;
47
48 DBusWrapper::DBusWrapper() :
49         pDbusDispatchCallback(this, &DBusWrapper::dbusDispatchCallback), //
50         pDbusFireCallback(this, &DBusWrapper::dbusFireCallback), //
51         pDbusCheckCallback(this, &DBusWrapper::dbusCheckCallback), //
52         pDbusTimerCallback(this, &DBusWrapper::dbusTimerCallback), //
53         mDbusConnection(0), //
54         mDBusError(), //
55         mNodesList(), //
56         mListTimerhandlePointer()
57 {
58     dbus_error_init(&mDBusError);
59     logInfo("DBusWrapper::DBusWrapper Opening DBus connection");
60     mDbusConnection = dbus_bus_get(DBUS_BUS_SESSION, &mDBusError);
61     if (dbus_error_is_set(&mDBusError))
62     {
63         logError("DBusWrapper::DBusWrapper Error while getting the DBus");
64         dbus_error_free(&mDBusError);
65     }
66     if (NULL == mDbusConnection)
67     {
68         logError("DBusWrapper::DBusWrapper DBus Connection is null");
69     }
70
71     //first, we are old enought to live longer then the connection:
72     dbus_connection_set_exit_on_disconnect(mDbusConnection, FALSE);
73
74     mObjectPathVTable.message_function = DBusWrapper::cbRootIntrospection;
75     dbus_connection_register_object_path(mDbusConnection, DBUS_SERVICE_OBJECT_PATH, &mObjectPathVTable, this);
76     int ret = dbus_bus_request_name(mDbusConnection, DBUS_SERVICE_PREFIX, DBUS_NAME_FLAG_DO_NOT_QUEUE, &mDBusError);
77     if (dbus_error_is_set(&mDBusError))
78     {
79         logError("DBusWrapper::DBusWrapper Name Error",mDBusError.message);
80         dbus_error_free(&mDBusError);
81     }
82     if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret)
83     {
84         logError("DBusWrapper::DBusWrapper Wrapper is not the Primary Owner",ret);
85         exit(1);
86     }
87 }
88
89 DBusWrapper::DBusWrapper(SocketHandler* socketHandler) :
90         pDbusDispatchCallback(this, &DBusWrapper::dbusDispatchCallback), //
91         pDbusFireCallback(this, &DBusWrapper::dbusFireCallback), //
92         pDbusCheckCallback(this, &DBusWrapper::dbusCheckCallback), //
93         pDbusTimerCallback(this, &DBusWrapper::dbusTimerCallback), //
94         mDbusConnection(0), //
95         mDBusError(), //
96         mNodesList(), //
97         mListTimerhandlePointer(), //
98         mSocketHandler(socketHandler)
99 {
100     assert(mSocketHandler!=0);
101
102     dbus_error_init(&mDBusError);
103     logInfo("DBusWrapper::DBusWrapper Opening DBus connection");
104     mDbusConnection = dbus_bus_get(DBUS_BUS_SESSION, &mDBusError);
105     if (dbus_error_is_set(&mDBusError))
106     {
107         logError("DBusWrapper::DBusWrapper Error while getting the DBus");
108         dbus_error_free(&mDBusError);
109     }
110     if (NULL == mDbusConnection)
111     {
112         logError("DBusWrapper::DBusWrapper DBus Connection is null");
113     }
114
115     //then we need to adopt the dbus to our mainloop:
116     //first, we are old enought to live longer then the connection:
117     dbus_connection_set_exit_on_disconnect(mDbusConnection, FALSE);
118
119     //we do not need the manual dispatching, since it is not allowed to call from a different thread. So leave it uncommented:
120     //dbus_connection_set_dispatch_status_function
121
122     //add watch functions:
123     dbus_bool_t watch = dbus_connection_set_watch_functions(mDbusConnection, addWatch, removeWatch, toogleWatch, this, NULL);
124     if (!watch)
125     {
126         logError("DBusWrapper::DBusWrapper Registering of watch functions failed");
127     }
128
129     //add timer functions:
130     dbus_bool_t timer = dbus_connection_set_timeout_functions(mDbusConnection, addTimeout, removeTimeout, toggleTimeout, this, NULL);
131     if (!timer)
132     {
133         logError("DBusWrapper::DBusWrapper Registering of timer functions failed");
134     }
135
136     //register callback for Introspectio
137     mObjectPathVTable.message_function = DBusWrapper::cbRootIntrospection;
138     dbus_connection_register_object_path(mDbusConnection, DBUS_SERVICE_OBJECT_PATH, &mObjectPathVTable, this);
139     int ret = dbus_bus_request_name(mDbusConnection, DBUS_SERVICE_PREFIX, DBUS_NAME_FLAG_DO_NOT_QUEUE, &mDBusError);
140     if (dbus_error_is_set(&mDBusError))
141     {
142         logError("DBusWrapper::DBusWrapper Name Error",mDBusError.message);
143         dbus_error_free(&mDBusError);
144     }
145     if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret)
146     {
147         logError("DBusWrapper::DBusWrapper Wrapper is not the Primary Owner",ret);
148         exit(1);
149     }
150 }
151
152 DBusWrapper::~DBusWrapper()
153 {
154     //close the connection again
155     logInfo("DBusWrapper::~DBusWrapper Closing DBus connection");
156     dbus_connection_unref(mDbusConnection);
157
158     //clean up all timerhandles we created but did not delete before
159     std::vector<sh_timerHandle_t*>::iterator it = mListTimerhandlePointer.begin();
160     for (; it != mListTimerhandlePointer.end(); ++it)
161     {
162         delete *it;
163     }
164 }
165
166 void DBusWrapper::registerCallback(const DBusObjectPathVTable* vtable, const std::string& path, void* userdata)
167 {
168     logInfo("DBusWrapper::~registerCallback register callback:",path);
169
170     std::string completePath = std::string(DBUS_SERVICE_OBJECT_PATH) + "/" + path;
171     dbus_error_init(&mDBusError);
172     mDbusConnection = dbus_bus_get(DBUS_BUS_SESSION, &mDBusError);
173     dbus_connection_register_object_path(mDbusConnection, completePath.c_str(), vtable, userdata);
174     if (dbus_error_is_set(&mDBusError))
175     {
176         logError("DBusWrapper::registerCallack error: ",mDBusError.message);
177         dbus_error_free(&mDBusError);
178     }
179     mNodesList.push_back(path);
180 }
181
182 DBusHandlerResult DBusWrapper::cbRootIntrospection(DBusConnection *conn, DBusMessage *msg, void *reference)
183 {
184     logInfo("DBusWrapper::~cbRootIntrospection called:");
185
186     mReference = (DBusWrapper*) reference;
187     std::list<std::string> nodesList = mReference->mNodesList;
188     DBusMessage * reply;
189     DBusMessageIter args;
190     dbus_uint32_t serial = 0;
191     if (dbus_message_is_method_call(msg, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
192     {
193         std::list<std::string>::iterator nodeIter = nodesList.begin();
194         const char *xml = ROOT_INTROSPECT_XML;
195         std::stringstream introspect;
196         introspect << std::string(xml);
197         for (; nodeIter != nodesList.end(); ++nodeIter)
198         {
199             introspect << "<node name='" << nodeIter->c_str() << "'/>";
200         }
201         introspect << "</node>";
202
203         reply = dbus_message_new_method_return(msg);
204         std::string s = introspect.str();
205         const char* string = s.c_str();
206
207         // add the arguments to the reply
208         dbus_message_iter_init_append(reply, &args);
209         if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &string))
210         {
211             logError("DBusWrapper::~cbRootIntrospection DBUS Out Of Memory!");
212         }
213
214         // send the reply && flush the connection
215         if (!dbus_connection_send(conn, reply, &serial))
216         {
217             logError("DBusWrapper::~cbRootIntrospection DBUS Out Of Memory!");
218         }
219         dbus_connection_flush(conn);
220         // free the reply
221         dbus_message_unref(reply);
222
223         return DBUS_HANDLER_RESULT_HANDLED;
224     }
225     else
226     {
227         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
228     }
229 }
230
231 void DBusWrapper::dbusMainLoop()
232 {
233     logInfo("DBusWrapper::dbusMainLoop Entering MainLoop");
234
235     while (dbus_connection_read_write_dispatch(mDbusConnection, -1))
236     {
237
238     }
239 }
240
241 void DBusWrapper::getDBusConnection(DBusConnection *& connection) const
242 {
243     connection = mDbusConnection;
244 }
245
246 dbus_bool_t DBusWrapper::addWatch(DBusWatch *watch, void *userData)
247 {
248     mReference = (DBusWrapper*) userData;
249     assert(mReference!=0);
250     return mReference->addWatchDelegate(watch, userData);
251 }
252
253 dbus_bool_t DBusWrapper::addWatchDelegate(DBusWatch * watch, void* userData)
254 {
255     (void) userData;
256     int16_t event = 0;
257     sh_pollHandle_t handle = 0;
258     uint flags = dbus_watch_get_flags(watch);
259
260     /* no watch flags for disabled watches */
261     if (dbus_watch_get_enabled(watch))
262     {
263         if (flags & DBUS_WATCH_READABLE)
264             event |= POLLIN;
265         if (flags & DBUS_WATCH_WRITABLE)
266             event |= POLLOUT;
267     }
268
269     logInfo("DBusWrapper::addWatchDelegate entered new watch, fd=",dbus_watch_get_unix_fd(watch),"event flag=",event);
270     am_Error_e error = mSocketHandler->addFDPoll(dbus_watch_get_unix_fd(watch), event, NULL, &pDbusFireCallback, &pDbusCheckCallback, &pDbusDispatchCallback, watch, handle);
271
272     //if everything is alright, add the watch and the handle to our map so we know this relationship
273     if (error == E_OK && handle != 0)
274     {
275         mMapHandleWatch.insert(std::make_pair(watch, handle));
276         return true;
277     }
278     logError("DBusWrapper::addWatchDelegate entering watch failed");
279     return (true);
280 }
281
282 void DBusWrapper::removeWatch(DBusWatch *watch, void *userData)
283 {
284     mReference = (DBusWrapper*) userData;
285     assert(mReference!=0);
286     mReference->removeWatchDelegate(watch, userData);
287 }
288
289 void DBusWrapper::removeWatchDelegate(DBusWatch *watch, void *userData)
290 {
291     (void) userData;
292     std::map<DBusWatch*, sh_pollHandle_t>::iterator iterator = mMapHandleWatch.begin();
293     iterator = mMapHandleWatch.find(watch);
294     if (iterator != mMapHandleWatch.end())
295         mSocketHandler->removeFDPoll(iterator->second);
296     logInfo("DBusWrapper::removeWatch removed watch with handle",iterator->second);
297     mMapHandleWatch.erase(iterator);
298 }
299
300 void DBusWrapper::toogleWatch(DBusWatch *watch, void *userData)
301 {
302     mReference = (DBusWrapper*) userData;
303     assert(mReference!=0);
304     mReference->toogleWatchDelegate(watch, userData);
305 }
306
307 void DBusWrapper::toogleWatchDelegate(DBusWatch *watch, void *userData)
308 {
309     (void) userData;
310     int16_t event = 0;
311     dbus_watch_get_unix_fd(watch);
312     uint flags = dbus_watch_get_flags(watch);
313     /* no watch flags for disabled watches */
314     if (dbus_watch_get_enabled(watch))
315     {
316         if (flags & DBUS_WATCH_READABLE)
317             event |= POLLIN;
318         if (flags & DBUS_WATCH_WRITABLE)
319             event |= POLLOUT;
320     }
321     std::map<DBusWatch*, sh_pollHandle_t>::iterator iterator = mMapHandleWatch.begin();
322     iterator = mMapHandleWatch.find(watch);
323     if (iterator != mMapHandleWatch.end())
324         mSocketHandler->updateEventFlags(iterator->second, event);
325     logInfo("DBusWrapper::toogleWatchDelegate watch was toggeled");
326 }
327
328 dbus_bool_t DBusWrapper::addTimeout(DBusTimeout *timeout, void* userData)
329 {
330     mReference = (DBusWrapper*) userData;
331     assert(mReference!=0);
332     return mReference->addTimeoutDelegate(timeout, userData);
333 }
334
335 dbus_bool_t DBusWrapper::addTimeoutDelegate(DBusTimeout *timeout, void* userData)
336 {
337     if (!dbus_timeout_get_enabled(timeout))
338         return false;
339
340     //calculate the timeout in timeval
341     timespec pollTimeout;
342     int localTimeout = dbus_timeout_get_interval(timeout);
343     pollTimeout.tv_sec = localTimeout / 1000;
344     pollTimeout.tv_nsec = (localTimeout % 1000) * 1000000;
345
346     //prepare handle and callback. new is eval, but there is no other choice because we need the pointer!
347     sh_timerHandle_t* handle = new sh_timerHandle_t;
348     mListTimerhandlePointer.push_back(handle);
349     shTimerCallBack* buffer = &pDbusTimerCallback;
350
351     //add the timer to the pollLoop
352     mSocketHandler->addTimer(pollTimeout, buffer, *handle, timeout);
353
354     //save the handle with dbus context
355     dbus_timeout_set_data(timeout, handle, NULL);
356
357     //save timeout in Socket context
358     userData = timeout;
359     logInfo("DBusWrapper::addTimeoutDelegate a timeout was added");
360     return true;
361 }
362
363 void DBusWrapper::removeTimeout(DBusTimeout *timeout, void* userData)
364 {
365     mReference = (DBusWrapper*) userData;
366     assert(mReference!=0);
367     mReference->removeTimeoutDelegate(timeout, userData);
368 }
369
370 void DBusWrapper::removeTimeoutDelegate(DBusTimeout *timeout, void* userData)
371 {
372     (void) userData;
373     //get the pointer to the handle and remove the timer
374     sh_timerHandle_t* handle = (sh_timerHandle_t*) dbus_timeout_get_data(timeout);
375     mSocketHandler->removeTimer(*handle);
376
377     //now go throught the timerlist and remove the pointer, free memory
378     std::vector<sh_timerHandle_t*>::iterator it = mListTimerhandlePointer.begin();
379     for (; it != mListTimerhandlePointer.end(); ++it)
380     {
381         if (*it == handle)
382         {
383             mListTimerhandlePointer.erase(it);
384             break;
385         }
386     }
387     delete handle;
388     logInfo("DBusWrapper::removeTimeoutDelegate a timeout was removed");
389 }
390
391 void DBusWrapper::toggleTimeout(DBusTimeout *timeout, void* userData)
392 {
393     mReference = (DBusWrapper*) userData;
394     assert(mReference!=0);
395     mReference->toggleTimeoutDelegate(timeout, userData);
396 }
397
398 bool am::DBusWrapper::dbusDispatchCallback(const sh_pollHandle_t handle, void *userData)
399 {
400     (void) handle;
401     (void) userData;
402     bool returnVal = true;
403     dbus_connection_ref(mDbusConnection);
404     if (dbus_connection_dispatch(mDbusConnection) == DBUS_DISPATCH_COMPLETE)
405         returnVal = false;
406     dbus_connection_unref(mDbusConnection);
407 //    logInfo("DBusWrapper::dbusDispatchCallback was called");
408     return returnVal;
409 }
410
411 bool am::DBusWrapper::dbusCheckCallback(const sh_pollHandle_t handle, void *userData)
412 {
413     (void) handle;
414     (void) userData;
415     bool returnVal = false;
416     dbus_connection_ref(mDbusConnection);
417     if (dbus_connection_get_dispatch_status(mDbusConnection) == DBUS_DISPATCH_DATA_REMAINS)
418         returnVal = true;
419     dbus_connection_unref(mDbusConnection);
420 //    logInfo("DBusWrapper::dbusCheckCallback was called");
421     return returnVal;
422 }
423
424 void am::DBusWrapper::dbusFireCallback(const pollfd pollfd, const sh_pollHandle_t handle, void *userData)
425 {
426     (void) handle;
427     (void) userData;
428     assert(userData!=NULL);
429     uint flags = 0;
430
431     if (pollfd.revents & POLLIN)
432         flags |= DBUS_WATCH_READABLE;
433     if (pollfd.revents & POLLOUT)
434         flags |= DBUS_WATCH_WRITABLE;
435     if (pollfd.revents & POLLHUP)
436         flags |= DBUS_WATCH_HANGUP;
437     if (pollfd.revents & POLLERR)
438         flags |= DBUS_WATCH_ERROR;
439
440     DBusWatch *watch = (DBusWatch*) userData;
441
442     dbus_connection_ref(mDbusConnection);
443     dbus_watch_handle(watch, flags);
444     dbus_connection_unref(mDbusConnection);
445 //    logInfo("DBusWrapper::dbusFireCallback was called");
446 }
447
448 void DBusWrapper::toggleTimeoutDelegate(DBusTimeout *timeout, void* userData)
449 {
450     (void) userData;
451     //get the pointer to the handle and remove the timer
452     sh_timerHandle_t* handle = (sh_timerHandle_t*) dbus_timeout_get_data(timeout);
453
454     //stop or restart?
455     if (dbus_timeout_get_enabled(timeout))
456     {
457         //calculate the timeout in timeval
458         timespec pollTimeout;
459         int localTimeout = dbus_timeout_get_interval(timeout);
460         pollTimeout.tv_sec = localTimeout / 1000;
461         pollTimeout.tv_nsec = (localTimeout % 1000) * 1000000;
462         mSocketHandler->restartTimer(*handle, pollTimeout);
463     }
464     else
465     {
466         mSocketHandler->stopTimer(*handle);
467     }logInfo("DBusWrapper::toggleTimeoutDelegate was called");
468 }
469
470 void DBusWrapper::dbusTimerCallback(sh_timerHandle_t handle, void *userData)
471 {
472     assert(userData!=NULL);
473     if (dbus_timeout_get_enabled((DBusTimeout*) userData))
474     {
475         timespec ts;
476         ts.tv_nsec = -1;
477         ts.tv_sec = -1;
478         mSocketHandler->restartTimer(handle, ts);
479     }
480     dbus_timeout_handle((DBusTimeout*) userData);
481     logInfo("DBusWrapper::dbusTimerCallback was called");
482 }
483