2 * Copyright (C) 2012, BMW AG
4 * This file is part of GENIVI Project AudioManager.
6 * Contributions are licensed to the GENIVI Alliance under one or more
7 * Contribution License Agreements.
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/.
15 * \author Christian Mueller, christian.ei.mueller@bmw.de BMW 2011,2012
17 * \file CAmDbusWrapper.cpp
18 * For further information see http://www.genivi.org/.
22 #include "shared/CAmDbusWrapper.h"
30 #include "shared/CAmDltWrapper.h"
31 #include "shared/CAmSocketHandler.h"
39 #define ROOT_INTROSPECT_XML \
40 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
42 "<interface name='org.AudioManager.freedesktop.DBus.Introspectable'>" \
43 "<method name='Introspect'>" \
44 " <arg name='xml_data' type='s' direction='out'/>" \
48 CAmDbusWrapper* CAmDbusWrapper::mpReference = NULL;
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), //
58 mpListTimerhandles(), //
59 mpSocketHandler(socketHandler)
61 assert(mpSocketHandler!=0);
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))
68 logError("DBusWrapper::DBusWrapper Error while getting the DBus");
69 dbus_error_free(&mDBusError);
71 if (NULL == mpDbusConnection)
73 logError("DBusWrapper::DBusWrapper DBus Connection is null");
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);
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
83 //add watch functions:
84 dbus_bool_t watch = dbus_connection_set_watch_functions(mpDbusConnection, addWatch, removeWatch, toogleWatch, this, NULL);
87 logError("DBusWrapper::DBusWrapper Registering of watch functions failed");
90 //add timer functions:
91 dbus_bool_t timer = dbus_connection_set_timeout_functions(mpDbusConnection, addTimeout, removeTimeout, toggleTimeout, this, NULL);
94 logError("DBusWrapper::DBusWrapper Registering of timer functions failed");
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))
103 logError("DBusWrapper::DBusWrapper Name Error", mDBusError.message);
104 dbus_error_free(&mDBusError);
106 if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret)
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?");
113 CAmDbusWrapper::~CAmDbusWrapper()
115 //close the connection again
116 logInfo("DBusWrapper::~DBusWrapper Closing DBus connection");
117 dbus_connection_unref(mpDbusConnection);
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)
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
134 void CAmDbusWrapper::registerCallback(const DBusObjectPathVTable* vtable, const std::string& path, void* userdata)
136 logInfo("DBusWrapper::registerCallback register callback:", path);
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))
144 logError("DBusWrapper::registerCallack error: ", mDBusError.message);
145 dbus_error_free(&mDBusError);
147 mListNodes.push_back(path);
151 * internal callback for the root introspection
157 DBusHandlerResult CAmDbusWrapper::cbRootIntrospection(DBusConnection *conn, DBusMessage *msg, void *reference)
159 logInfo("DBusWrapper::~cbRootIntrospection called:");
161 mpReference = (CAmDbusWrapper*) reference;
162 std::vector<std::string> nodesList = mpReference->mListNodes;
164 DBusMessageIter args;
165 dbus_uint32_t serial = 0;
166 if (dbus_message_is_method_call(msg, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
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)
174 introspect << "<node name='" << nodeIter->c_str() << "'/>";
176 introspect << "</node>";
178 reply = dbus_message_new_method_return(msg);
179 std::string s = introspect.str();
180 const char* string = s.c_str();
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))
186 logError("DBusWrapper::~cbRootIntrospection DBUS Out Of Memory!");
189 // send the reply && flush the connection
190 if (!dbus_connection_send(conn, reply, &serial))
192 logError("DBusWrapper::~cbRootIntrospection DBUS Out Of Memory!");
194 dbus_connection_flush(conn);
196 dbus_message_unref(reply);
198 return (DBUS_HANDLER_RESULT_HANDLED);
202 return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
207 * returns the dbus connection
208 * @param connection pointer to the connection
210 void CAmDbusWrapper::getDBusConnection(DBusConnection *& connection) const
212 connection = mpDbusConnection;
215 dbus_bool_t CAmDbusWrapper::addWatch(DBusWatch *watch, void *userData)
217 mpReference = (CAmDbusWrapper*) userData;
218 assert(mpReference!=0);
219 return (mpReference->addWatchDelegate(watch, userData));
222 dbus_bool_t CAmDbusWrapper::addWatchDelegate(DBusWatch * watch, void* userData)
226 sh_pollHandle_t handle = 0;
227 uint flags = dbus_watch_get_flags(watch);
229 /* no watch flags for disabled watches */
230 if (dbus_watch_get_enabled(watch))
232 if (flags & DBUS_WATCH_READABLE)
234 if (flags & DBUS_WATCH_WRITABLE)
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);
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)
244 mMapHandleWatch.insert(std::make_pair(watch, handle));
247 logError("DBusWrapper::addWatchDelegate entering watch failed");
251 void CAmDbusWrapper::removeWatch(DBusWatch *watch, void *userData)
253 mpReference = (CAmDbusWrapper*) userData;
254 assert(mpReference!=0);
255 mpReference->removeWatchDelegate(watch, userData);
258 void CAmDbusWrapper::removeWatchDelegate(DBusWatch *watch, void *userData)
261 std::map<DBusWatch*, sh_pollHandle_t>::iterator iterator = mMapHandleWatch.begin();
262 iterator = mMapHandleWatch.find(watch);
263 if (iterator != mMapHandleWatch.end())
265 mpSocketHandler->removeFDPoll(iterator->second);
266 logInfo("DBusWrapper::removeWatch removed watch with handle", iterator->second);
267 mMapHandleWatch.erase(iterator);
271 logError("DBusWrapper::removeWatch could not find handle !");
275 void CAmDbusWrapper::toogleWatch(DBusWatch *watch, void *userData)
277 mpReference = (CAmDbusWrapper*) userData;
278 assert(mpReference!=0);
279 mpReference->toogleWatchDelegate(watch, userData);
282 void CAmDbusWrapper::toogleWatchDelegate(DBusWatch *watch, void *userData)
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))
291 if (flags & DBUS_WATCH_READABLE)
293 if (flags & DBUS_WATCH_WRITABLE)
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");
303 dbus_bool_t CAmDbusWrapper::addTimeout(DBusTimeout *timeout, void* userData)
305 mpReference = (CAmDbusWrapper*) userData;
306 assert(mpReference!=0);
307 return (mpReference->addTimeoutDelegate(timeout, userData));
310 dbus_bool_t CAmDbusWrapper::addTimeoutDelegate(DBusTimeout *timeout, void* userData)
314 if (!dbus_timeout_get_enabled(timeout))
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;
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);
327 //add the timer to the pollLoop
328 mpSocketHandler->addTimer(pollTimeout, &pDbusTimerCallback, *handle, timeout);
330 //save the handle with dbus context
331 dbus_timeout_set_data(timeout, handle, NULL);
333 //save timeout in Socket context
335 logInfo("DBusWrapper::addTimeoutDelegate a timeout was added, timeout",localTimeout," handle ", *handle);
339 void CAmDbusWrapper::removeTimeout(DBusTimeout *timeout, void* userData)
341 mpReference = (CAmDbusWrapper*) userData;
342 assert(mpReference!=0);
343 mpReference->removeTimeoutDelegate(timeout, userData);
346 void CAmDbusWrapper::removeTimeoutDelegate(DBusTimeout *timeout, 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);
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)
359 mpListTimerhandles.erase(it);
364 logInfo("DBusWrapper::removeTimeoutDelegate a timeout was removed");
367 void CAmDbusWrapper::toggleTimeout(DBusTimeout *timeout, void* userData)
369 mpReference = (CAmDbusWrapper*) userData;
370 assert(mpReference!=0);
371 mpReference->toggleTimeoutDelegate(timeout, userData);
374 bool am::CAmDbusWrapper::dbusDispatchCallback(const sh_pollHandle_t handle, void *userData)
378 bool returnVal = true;
379 dbus_connection_ref(mpDbusConnection);
380 if (dbus_connection_dispatch(mpDbusConnection) == DBUS_DISPATCH_COMPLETE)
382 dbus_connection_unref(mpDbusConnection);
383 //logInfo("DBusWrapper::dbusDispatchCallback was called");
387 bool am::CAmDbusWrapper::dbusCheckCallback(const sh_pollHandle_t handle, void *userData)
391 bool returnVal = false;
392 dbus_connection_ref(mpDbusConnection);
393 if (dbus_connection_get_dispatch_status(mpDbusConnection) == DBUS_DISPATCH_DATA_REMAINS)
395 dbus_connection_unref(mpDbusConnection);
396 //logInfo("DBusWrapper::dbusCheckCallback was called");
400 void am::CAmDbusWrapper::dbusFireCallback(const pollfd pollfd, const sh_pollHandle_t handle, void *userData)
404 assert(userData!=NULL);
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;
416 DBusWatch *watch = (DBusWatch*) userData;
418 dbus_connection_ref(mpDbusConnection);
419 dbus_watch_handle(watch, flags);
420 dbus_connection_unref(mpDbusConnection);
421 //logInfo("DBusWrapper::dbusFireCallback was called");
424 void CAmDbusWrapper::toggleTimeoutDelegate(DBusTimeout *timeout, 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);
431 if (dbus_timeout_get_enabled(timeout))
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);
442 mpSocketHandler->stopTimer(*handle);
444 logInfo("DBusWrapper::toggleTimeoutDelegate was called");
447 void CAmDbusWrapper::dbusTimerCallback(sh_timerHandle_t handle, void *userData)
449 logInfo("DBusWrapper::dbusTimerCallback was called");
450 assert(userData!=NULL);
451 if (dbus_timeout_get_enabled((DBusTimeout*) userData))
453 mpSocketHandler->restartTimer(handle);
455 dbus_timeout_handle((DBusTimeout*) userData);