* [GAM-74] resolving issues found by coverity scan
[profile/ivi/genivi/genivi-audio-manager.git] / AudioManagerDaemon / src / CAmDbusWrapper.cpp
1 /**
2  * Copyright (C) 2012, BMW AG
3  *
4  * This file is part of GENIVI Project AudioManager.
5  *
6  * Contributions are licensed to the GENIVI Alliance under one or more
7  * Contribution License Agreements.
8  *
9  * \copyright
10  * This Source Code Form is subject to the terms of the
11  * Mozilla Public License, v. 2.0. If a  copy of the MPL was not distributed with
12  * this file, You can obtain one at http://mozilla.org/MPL/2.0/.
13  *
14  *
15  * \author Christian Mueller, christian.ei.mueller@bmw.de BMW 2011,2012
16  *
17  * \file CAmDbusWrapper.cpp
18  * For further information see http://www.genivi.org/.
19  *
20  */
21
22 #include "shared/CAmDbusWrapper.h"
23 #include <config.h>
24 #include <fstream>
25 #include <sstream>
26 #include <string>
27 #include <cassert>
28 #include <cstdlib>
29 #include <stdexcept>
30 #include "shared/CAmDltWrapper.h"
31 #include "shared/CAmSocketHandler.h"
32
33 namespace am
34 {
35
36 /**
37  * introspectio header
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 CAmDbusWrapper* CAmDbusWrapper::mpReference = NULL;
49
50 CAmDbusWrapper::CAmDbusWrapper(CAmSocketHandler* socketHandler, DBusBusType type) :
51         pDbusDispatchCallback(this, &CAmDbusWrapper::dbusDispatchCallback), //
52         pDbusFireCallback(this, &CAmDbusWrapper::dbusFireCallback), //
53         pDbusCheckCallback(this, &CAmDbusWrapper::dbusCheckCallback), //
54         pDbusTimerCallback(this, &CAmDbusWrapper::dbusTimerCallback), //
55         mpDbusConnection(0), //
56         mDBusError(), //
57         mListNodes(), //
58         mpListTimerhandles(), //
59         mpSocketHandler(socketHandler)
60 {
61     assert(mpSocketHandler!=0);
62
63     dbus_error_init(&mDBusError);
64     logInfo("DBusWrapper::DBusWrapper Opening DBus connection");
65     mpDbusConnection = dbus_bus_get(type, &mDBusError);
66     if (dbus_error_is_set(&mDBusError))
67     {
68         logError("DBusWrapper::DBusWrapper Error while getting the DBus");
69         dbus_error_free(&mDBusError);
70     }
71     if (NULL == mpDbusConnection)
72     {
73         logError("DBusWrapper::DBusWrapper DBus Connection is null");
74     }
75
76     //then we need to adopt the dbus to our mainloop:
77     //first, we are old enought to live longer then the connection:
78     dbus_connection_set_exit_on_disconnect(mpDbusConnection, FALSE);
79
80     //we do not need the manual dispatching, since it is not allowed to call from a different thread. So leave it uncommented:
81     //dbus_connection_set_dispatch_status_function
82
83     //add watch functions:
84     dbus_bool_t watch = dbus_connection_set_watch_functions(mpDbusConnection, addWatch, removeWatch, toogleWatch, this, NULL);
85     if (!watch)
86     {
87         logError("DBusWrapper::DBusWrapper Registering of watch functions failed");
88     }
89
90     //add timer functions:
91     dbus_bool_t timer = dbus_connection_set_timeout_functions(mpDbusConnection, addTimeout, removeTimeout, toggleTimeout, this, NULL);
92     if (!timer)
93     {
94         logError("DBusWrapper::DBusWrapper Registering of timer functions failed");
95     }
96
97     //register callback for Introspectio
98     mObjectPathVTable.message_function = CAmDbusWrapper::cbRootIntrospection;
99     dbus_connection_register_object_path(mpDbusConnection, DBUS_SERVICE_OBJECT_PATH, &mObjectPathVTable, this);
100     int ret = dbus_bus_request_name(mpDbusConnection, DBUS_SERVICE_PREFIX, DBUS_NAME_FLAG_DO_NOT_QUEUE, &mDBusError);
101     if (dbus_error_is_set(&mDBusError))
102     {
103         logError("DBusWrapper::DBusWrapper Name Error", mDBusError.message);
104         dbus_error_free(&mDBusError);
105     }
106     if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret)
107     {
108         logError("DBusWrapper::DBusWrapper Wrapper is not the Primary Owner ! Another instance already running?");
109         throw std::runtime_error("DBusWrapper::DBusWrapper Wrapper is not the Primary Owner ! Another instance already running?");
110     }
111 }
112
113 CAmDbusWrapper::~CAmDbusWrapper()
114 {
115     //close the connection again
116     logInfo("DBusWrapper::~DBusWrapper Closing DBus connection");
117     dbus_connection_unref(mpDbusConnection);
118
119     //clean up all timerhandles we created but did not delete before
120     std::vector<sh_timerHandle_t*>::iterator it = mpListTimerhandles.begin();
121     for (; it != mpListTimerhandles.end(); ++it)
122     {
123         delete *it;
124     }
125 }
126
127 /**
128  * registers a callback that is entered as path below the main path.
129  * The configuration of the mainpath is done via DBusConfiguration.h
130  * @param vtable the vtable that holds a pointer to the callback that is called when the path is called from the dbus
131  * @param path the name of the path
132  * @param userdata pointer to the class that will handle the callback
133  */
134 void CAmDbusWrapper::registerCallback(const DBusObjectPathVTable* vtable, const std::string& path, void* userdata)
135 {
136     logInfo("DBusWrapper::registerCallback register callback:", path);
137
138     std::string completePath = std::string(DBUS_SERVICE_OBJECT_PATH) + "/" + path;
139     dbus_error_init(&mDBusError);
140     mpDbusConnection = dbus_bus_get(DBUS_BUS_SESSION, &mDBusError);
141     dbus_connection_register_object_path(mpDbusConnection, completePath.c_str(), vtable, userdata);
142     if (dbus_error_is_set(&mDBusError))
143     {
144         logError("DBusWrapper::registerCallack error: ", mDBusError.message);
145         dbus_error_free(&mDBusError);
146     }
147     mListNodes.push_back(path);
148 }
149
150 /**
151  * internal callback for the root introspection
152  * @param conn
153  * @param msg
154  * @param reference
155  * @return
156  */
157 DBusHandlerResult CAmDbusWrapper::cbRootIntrospection(DBusConnection *conn, DBusMessage *msg, void *reference)
158 {
159     logInfo("DBusWrapper::~cbRootIntrospection called:");
160
161     mpReference = (CAmDbusWrapper*) reference;
162     std::vector<std::string> nodesList = mpReference->mListNodes;
163     DBusMessage * reply;
164     DBusMessageIter args;
165     dbus_uint32_t serial = 0;
166     if (dbus_message_is_method_call(msg, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
167     {
168         std::vector<std::string>::iterator nodeIter = nodesList.begin();
169         const char *xml = ROOT_INTROSPECT_XML;
170         std::stringstream introspect;
171         introspect << std::string(xml);
172         for (; nodeIter != nodesList.end(); ++nodeIter)
173         {
174             introspect << "<node name='" << nodeIter->c_str() << "'/>";
175         }
176         introspect << "</node>";
177
178         reply = dbus_message_new_method_return(msg);
179         std::string s = introspect.str();
180         const char* string = s.c_str();
181
182         // add the arguments to the reply
183         dbus_message_iter_init_append(reply, &args);
184         if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &string))
185         {
186             logError("DBusWrapper::~cbRootIntrospection DBUS Out Of Memory!");
187         }
188
189         // send the reply && flush the connection
190         if (!dbus_connection_send(conn, reply, &serial))
191         {
192             logError("DBusWrapper::~cbRootIntrospection DBUS Out Of Memory!");
193         }
194         dbus_connection_flush(conn);
195         // free the reply
196         dbus_message_unref(reply);
197
198         return (DBUS_HANDLER_RESULT_HANDLED);
199     }
200     else
201     {
202         return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
203     }
204 }
205
206 /**
207  * returns the dbus connection
208  * @param connection pointer to the connection
209  */
210 void CAmDbusWrapper::getDBusConnection(DBusConnection *& connection) const
211 {
212     connection = mpDbusConnection;
213 }
214
215 dbus_bool_t CAmDbusWrapper::addWatch(DBusWatch *watch, void *userData)
216 {
217     mpReference = (CAmDbusWrapper*) userData;
218     assert(mpReference!=0);
219     return (mpReference->addWatchDelegate(watch, userData));
220 }
221
222 dbus_bool_t CAmDbusWrapper::addWatchDelegate(DBusWatch * watch, void* userData)
223 {
224     (void) userData;
225     int16_t event = 0;
226     sh_pollHandle_t handle = 0;
227     uint flags = dbus_watch_get_flags(watch);
228
229     /* no watch flags for disabled watches */
230     if (dbus_watch_get_enabled(watch))
231     {
232         if (flags & DBUS_WATCH_READABLE)
233             event |= POLLIN;
234         if (flags & DBUS_WATCH_WRITABLE)
235             event |= POLLOUT;
236     }
237
238     logInfo("DBusWrapper::addWatchDelegate entered new watch, fd=", dbus_watch_get_unix_fd(watch), "event flag=", event);
239     am_Error_e error = mpSocketHandler->addFDPoll(dbus_watch_get_unix_fd(watch), event, NULL, &pDbusFireCallback, &pDbusCheckCallback, &pDbusDispatchCallback, watch, handle);
240
241     //if everything is alright, add the watch and the handle to our map so we know this relationship
242     if (error == E_OK && handle != 0)
243     {
244         mMapHandleWatch.insert(std::make_pair(watch, handle));
245         return (true);
246     }
247     logError("DBusWrapper::addWatchDelegate entering watch failed");
248     return (true);
249 }
250
251 void CAmDbusWrapper::removeWatch(DBusWatch *watch, void *userData)
252 {
253     mpReference = (CAmDbusWrapper*) userData;
254     assert(mpReference!=0);
255     mpReference->removeWatchDelegate(watch, userData);
256 }
257
258 void CAmDbusWrapper::removeWatchDelegate(DBusWatch *watch, void *userData)
259 {
260     (void) userData;
261     std::map<DBusWatch*, sh_pollHandle_t>::iterator iterator = mMapHandleWatch.begin();
262     iterator = mMapHandleWatch.find(watch);
263     if (iterator != mMapHandleWatch.end())
264     {
265         mpSocketHandler->removeFDPoll(iterator->second);
266         logInfo("DBusWrapper::removeWatch removed watch with handle", iterator->second);
267         mMapHandleWatch.erase(iterator);
268     }
269     else
270     {
271         logError("DBusWrapper::removeWatch could not find handle !");
272     }
273 }
274
275 void CAmDbusWrapper::toogleWatch(DBusWatch *watch, void *userData)
276 {
277     mpReference = (CAmDbusWrapper*) userData;
278     assert(mpReference!=0);
279     mpReference->toogleWatchDelegate(watch, userData);
280 }
281
282 void CAmDbusWrapper::toogleWatchDelegate(DBusWatch *watch, void *userData)
283 {
284     (void) userData;
285     int16_t event = 0;
286     dbus_watch_get_unix_fd(watch);
287     uint flags = dbus_watch_get_flags(watch);
288     /* no watch flags for disabled watches */
289     if (dbus_watch_get_enabled(watch))
290     {
291         if (flags & DBUS_WATCH_READABLE)
292             event |= POLLIN;
293         if (flags & DBUS_WATCH_WRITABLE)
294             event |= POLLOUT;
295     }
296     std::map<DBusWatch*, sh_pollHandle_t>::iterator iterator = mMapHandleWatch.begin();
297     iterator = mMapHandleWatch.find(watch);
298     if (iterator != mMapHandleWatch.end())
299         mpSocketHandler->updateEventFlags(iterator->second, event);
300     logInfo("DBusWrapper::toogleWatchDelegate watch was toggeled");
301 }
302
303 dbus_bool_t CAmDbusWrapper::addTimeout(DBusTimeout *timeout, void* userData)
304 {
305     mpReference = (CAmDbusWrapper*) userData;
306     assert(mpReference!=0);
307     return (mpReference->addTimeoutDelegate(timeout, userData));
308 }
309
310 dbus_bool_t CAmDbusWrapper::addTimeoutDelegate(DBusTimeout *timeout, void* userData)
311 {
312     (void)userData;
313
314     if (!dbus_timeout_get_enabled(timeout))
315         return (false);
316
317     //calculate the timeout in timeval
318     timespec pollTimeout;
319     int localTimeout = dbus_timeout_get_interval(timeout);
320     pollTimeout.tv_sec = localTimeout / 1000;
321     pollTimeout.tv_nsec = (localTimeout % 1000) * 1000000;
322
323     //prepare handle and callback. new is eval, but there is no other choice because we need the pointer!
324     sh_timerHandle_t* handle = new sh_timerHandle_t;
325     mpListTimerhandles.push_back(handle);
326
327     //add the timer to the pollLoop
328     mpSocketHandler->addTimer(pollTimeout, &pDbusTimerCallback, *handle, timeout);
329
330     //save the handle with dbus context
331     dbus_timeout_set_data(timeout, handle, NULL);
332
333     //save timeout in Socket context
334     userData = timeout;
335     logInfo("DBusWrapper::addTimeoutDelegate a timeout was added, timeout",localTimeout," handle ", *handle);
336     return (true);
337 }
338
339 void CAmDbusWrapper::removeTimeout(DBusTimeout *timeout, void* userData)
340 {
341     mpReference = (CAmDbusWrapper*) userData;
342     assert(mpReference!=0);
343     mpReference->removeTimeoutDelegate(timeout, userData);
344 }
345
346 void CAmDbusWrapper::removeTimeoutDelegate(DBusTimeout *timeout, void* userData)
347 {
348     (void) userData;
349     //get the pointer to the handle and remove the timer
350     sh_timerHandle_t* handle = (sh_timerHandle_t*) dbus_timeout_get_data(timeout);
351     mpSocketHandler->removeTimer(*handle);
352
353     //now go throught the timerlist and remove the pointer, free memory
354     std::vector<sh_timerHandle_t*>::iterator it = mpListTimerhandles.begin();
355     for (; it != mpListTimerhandles.end(); ++it)
356     {
357         if (*it == handle)
358         {
359             mpListTimerhandles.erase(it);
360             break;
361         }
362     }
363     delete handle;
364     logInfo("DBusWrapper::removeTimeoutDelegate a timeout was removed");
365 }
366
367 void CAmDbusWrapper::toggleTimeout(DBusTimeout *timeout, void* userData)
368 {
369     mpReference = (CAmDbusWrapper*) userData;
370     assert(mpReference!=0);
371     mpReference->toggleTimeoutDelegate(timeout, userData);
372 }
373
374 bool am::CAmDbusWrapper::dbusDispatchCallback(const sh_pollHandle_t handle, void *userData)
375 {
376     (void) handle;
377     (void) userData;
378     bool returnVal = true;
379     dbus_connection_ref(mpDbusConnection);
380     if (dbus_connection_dispatch(mpDbusConnection) == DBUS_DISPATCH_COMPLETE)
381         returnVal = false;
382     dbus_connection_unref(mpDbusConnection);
383     //logInfo("DBusWrapper::dbusDispatchCallback was called");
384     return (returnVal);
385 }
386
387 bool am::CAmDbusWrapper::dbusCheckCallback(const sh_pollHandle_t handle, void *userData)
388 {
389     (void) handle;
390     (void) userData;
391     bool returnVal = false;
392     dbus_connection_ref(mpDbusConnection);
393     if (dbus_connection_get_dispatch_status(mpDbusConnection) == DBUS_DISPATCH_DATA_REMAINS)
394         returnVal = true;
395     dbus_connection_unref(mpDbusConnection);
396     //logInfo("DBusWrapper::dbusCheckCallback was called");
397     return (returnVal);
398 }
399
400 void am::CAmDbusWrapper::dbusFireCallback(const pollfd pollfd, const sh_pollHandle_t handle, void *userData)
401 {
402     (void) handle;
403     (void) userData;
404     assert(userData!=NULL);
405     uint flags = 0;
406
407     if (pollfd.revents & POLLIN)
408         flags |= DBUS_WATCH_READABLE;
409     if (pollfd.revents & POLLOUT)
410         flags |= DBUS_WATCH_WRITABLE;
411     if (pollfd.revents & POLLHUP)
412         flags |= DBUS_WATCH_HANGUP;
413     if (pollfd.revents & POLLERR)
414         flags |= DBUS_WATCH_ERROR;
415
416     DBusWatch *watch = (DBusWatch*) userData;
417
418     dbus_connection_ref(mpDbusConnection);
419     dbus_watch_handle(watch, flags);
420     dbus_connection_unref(mpDbusConnection);
421     //logInfo("DBusWrapper::dbusFireCallback was called");
422 }
423
424 void CAmDbusWrapper::toggleTimeoutDelegate(DBusTimeout *timeout, void* userData)
425 {
426     (void) userData;
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         mpSocketHandler->updateTimer(*handle, pollTimeout);
439     }
440     else
441     {
442         mpSocketHandler->stopTimer(*handle);
443     }
444     logInfo("DBusWrapper::toggleTimeoutDelegate was called");
445 }
446
447 void CAmDbusWrapper::dbusTimerCallback(sh_timerHandle_t handle, void *userData)
448 {
449     logInfo("DBusWrapper::dbusTimerCallback was called");
450     assert(userData!=NULL);
451     if (dbus_timeout_get_enabled((DBusTimeout*) userData))
452     {
453         mpSocketHandler->restartTimer(handle);
454     }
455     dbus_timeout_handle((DBusTimeout*) userData);
456 }
457 }
458