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"
29 #include "shared/CAmDltWrapper.h"
30 #include "shared/CAmSocketHandler.h"
38 #define ROOT_INTROSPECT_XML \
39 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
41 "<interface name='org.AudioManager.freedesktop.DBus.Introspectable'>" \
42 "<method name='Introspect'>" \
43 " <arg name='xml_data' type='s' direction='out'/>" \
47 CAmDbusWrapper* CAmDbusWrapper::mpReference = NULL;
49 CAmDbusWrapper::CAmDbusWrapper(CAmSocketHandler* socketHandler) :
50 pDbusDispatchCallback(this, &CAmDbusWrapper::dbusDispatchCallback), //
51 pDbusFireCallback(this, &CAmDbusWrapper::dbusFireCallback), //
52 pDbusCheckCallback(this, &CAmDbusWrapper::dbusCheckCallback), //
53 pDbusTimerCallback(this, &CAmDbusWrapper::dbusTimerCallback), //
54 mpDbusConnection(0), //
57 mpListTimerhandles(), //
58 mpSocketHandler(socketHandler)
60 assert(mpSocketHandler!=0);
62 dbus_error_init(&mDBusError);
63 logInfo("DBusWrapper::DBusWrapper Opening DBus connection");
64 mpDbusConnection = dbus_bus_get(DBUS_BUS_SESSION, &mDBusError);
65 if (dbus_error_is_set(&mDBusError))
67 logError("DBusWrapper::DBusWrapper Error while getting the DBus");
68 dbus_error_free(&mDBusError);
70 if (NULL == mpDbusConnection)
72 logError("DBusWrapper::DBusWrapper DBus Connection is null");
75 //then we need to adopt the dbus to our mainloop:
76 //first, we are old enought to live longer then the connection:
77 dbus_connection_set_exit_on_disconnect(mpDbusConnection, FALSE);
79 //we do not need the manual dispatching, since it is not allowed to call from a different thread. So leave it uncommented:
80 //dbus_connection_set_dispatch_status_function
82 //add watch functions:
83 dbus_bool_t watch = dbus_connection_set_watch_functions(mpDbusConnection, addWatch, removeWatch, toogleWatch, this, NULL);
86 logError("DBusWrapper::DBusWrapper Registering of watch functions failed");
89 //add timer functions:
90 dbus_bool_t timer = dbus_connection_set_timeout_functions(mpDbusConnection, addTimeout, removeTimeout, toggleTimeout, this, NULL);
93 logError("DBusWrapper::DBusWrapper Registering of timer functions failed");
96 //register callback for Introspectio
97 mObjectPathVTable.message_function = CAmDbusWrapper::cbRootIntrospection;
98 dbus_connection_register_object_path(mpDbusConnection, DBUS_SERVICE_OBJECT_PATH, &mObjectPathVTable, this);
99 int ret = dbus_bus_request_name(mpDbusConnection, DBUS_SERVICE_PREFIX, DBUS_NAME_FLAG_DO_NOT_QUEUE, &mDBusError);
100 if (dbus_error_is_set(&mDBusError))
102 logError("DBusWrapper::DBusWrapper Name Error", mDBusError.message);
103 dbus_error_free(&mDBusError);
105 if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret)
107 logError("DBusWrapper::DBusWrapper Wrapper is not the Primary Owner ! Another instance already running?", ret);
112 CAmDbusWrapper::~CAmDbusWrapper()
114 //close the connection again
115 logInfo("DBusWrapper::~DBusWrapper Closing DBus connection");
116 dbus_connection_unref(mpDbusConnection);
118 //clean up all timerhandles we created but did not delete before
119 std::vector<sh_timerHandle_t*>::iterator it = mpListTimerhandles.begin();
120 for (; it != mpListTimerhandles.end(); ++it)
127 * registers a callback that is entered as path below the main path.
128 * The configuration of the mainpath is done via DBusConfiguration.h
129 * @param vtable the vtable that holds a pointer to the callback that is called when the path is called from the dbus
130 * @param path the name of the path
131 * @param userdata pointer to the class that will handle the callback
133 void CAmDbusWrapper::registerCallback(const DBusObjectPathVTable* vtable, const std::string& path, void* userdata)
135 logInfo("DBusWrapper::~registerCallback register callback:", path);
137 std::string completePath = std::string(DBUS_SERVICE_OBJECT_PATH) + "/" + path;
138 dbus_error_init(&mDBusError);
139 mpDbusConnection = dbus_bus_get(DBUS_BUS_SESSION, &mDBusError);
140 dbus_connection_register_object_path(mpDbusConnection, completePath.c_str(), vtable, userdata);
141 if (dbus_error_is_set(&mDBusError))
143 logError("DBusWrapper::registerCallack error: ", mDBusError.message);
144 dbus_error_free(&mDBusError);
146 mListNodes.push_back(path);
150 * internal callback for the root introspection
156 DBusHandlerResult CAmDbusWrapper::cbRootIntrospection(DBusConnection *conn, DBusMessage *msg, void *reference)
158 logInfo("DBusWrapper::~cbRootIntrospection called:");
160 mpReference = (CAmDbusWrapper*) reference;
161 std::list<std::string> nodesList = mpReference->mListNodes;
163 DBusMessageIter args;
164 dbus_uint32_t serial = 0;
165 if (dbus_message_is_method_call(msg, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
167 std::list<std::string>::iterator nodeIter = nodesList.begin();
168 const char *xml = ROOT_INTROSPECT_XML;
169 std::stringstream introspect;
170 introspect << std::string(xml);
171 for (; nodeIter != nodesList.end(); ++nodeIter)
173 introspect << "<node name='" << nodeIter->c_str() << "'/>";
175 introspect << "</node>";
177 reply = dbus_message_new_method_return(msg);
178 std::string s = introspect.str();
179 const char* string = s.c_str();
181 // add the arguments to the reply
182 dbus_message_iter_init_append(reply, &args);
183 if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &string))
185 logError("DBusWrapper::~cbRootIntrospection DBUS Out Of Memory!");
188 // send the reply && flush the connection
189 if (!dbus_connection_send(conn, reply, &serial))
191 logError("DBusWrapper::~cbRootIntrospection DBUS Out Of Memory!");
193 dbus_connection_flush(conn);
195 dbus_message_unref(reply);
197 return (DBUS_HANDLER_RESULT_HANDLED);
201 return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
206 * returns the dbus connection
207 * @param connection pointer to the connection
209 void CAmDbusWrapper::getDBusConnection(DBusConnection *& connection) const
211 connection = mpDbusConnection;
214 dbus_bool_t CAmDbusWrapper::addWatch(DBusWatch *watch, void *userData)
216 mpReference = (CAmDbusWrapper*) userData;
217 assert(mpReference!=0);
218 return (mpReference->addWatchDelegate(watch, userData));
221 dbus_bool_t CAmDbusWrapper::addWatchDelegate(DBusWatch * watch, void* userData)
225 sh_pollHandle_t handle = 0;
226 uint flags = dbus_watch_get_flags(watch);
228 /* no watch flags for disabled watches */
229 if (dbus_watch_get_enabled(watch))
231 if (flags & DBUS_WATCH_READABLE)
233 if (flags & DBUS_WATCH_WRITABLE)
237 logInfo("DBusWrapper::addWatchDelegate entered new watch, fd=", dbus_watch_get_unix_fd(watch), "event flag=", event);
238 am_Error_e error = mpSocketHandler->addFDPoll(dbus_watch_get_unix_fd(watch), event, NULL, &pDbusFireCallback, &pDbusCheckCallback, &pDbusDispatchCallback, watch, handle);
240 //if everything is alright, add the watch and the handle to our map so we know this relationship
241 if (error == E_OK && handle != 0)
243 mMapHandleWatch.insert(std::make_pair(watch, handle));
246 logError("DBusWrapper::addWatchDelegate entering watch failed");
250 void CAmDbusWrapper::removeWatch(DBusWatch *watch, void *userData)
252 mpReference = (CAmDbusWrapper*) userData;
253 assert(mpReference!=0);
254 mpReference->removeWatchDelegate(watch, userData);
257 void CAmDbusWrapper::removeWatchDelegate(DBusWatch *watch, void *userData)
260 std::map<DBusWatch*, sh_pollHandle_t>::iterator iterator = mMapHandleWatch.begin();
261 iterator = mMapHandleWatch.find(watch);
262 if (iterator != mMapHandleWatch.end())
263 mpSocketHandler->removeFDPoll(iterator->second);
264 logInfo("DBusWrapper::removeWatch removed watch with handle", iterator->second);
265 mMapHandleWatch.erase(iterator);
268 void CAmDbusWrapper::toogleWatch(DBusWatch *watch, void *userData)
270 mpReference = (CAmDbusWrapper*) userData;
271 assert(mpReference!=0);
272 mpReference->toogleWatchDelegate(watch, userData);
275 void CAmDbusWrapper::toogleWatchDelegate(DBusWatch *watch, void *userData)
279 dbus_watch_get_unix_fd(watch);
280 uint flags = dbus_watch_get_flags(watch);
281 /* no watch flags for disabled watches */
282 if (dbus_watch_get_enabled(watch))
284 if (flags & DBUS_WATCH_READABLE)
286 if (flags & DBUS_WATCH_WRITABLE)
289 std::map<DBusWatch*, sh_pollHandle_t>::iterator iterator = mMapHandleWatch.begin();
290 iterator = mMapHandleWatch.find(watch);
291 if (iterator != mMapHandleWatch.end())
292 mpSocketHandler->updateEventFlags(iterator->second, event);
293 logInfo("DBusWrapper::toogleWatchDelegate watch was toggeled");
296 dbus_bool_t CAmDbusWrapper::addTimeout(DBusTimeout *timeout, void* userData)
298 mpReference = (CAmDbusWrapper*) userData;
299 assert(mpReference!=0);
300 return (mpReference->addTimeoutDelegate(timeout, userData));
303 dbus_bool_t CAmDbusWrapper::addTimeoutDelegate(DBusTimeout *timeout, void* userData)
305 if (!dbus_timeout_get_enabled(timeout))
308 //calculate the timeout in timeval
309 timespec pollTimeout;
310 int localTimeout = dbus_timeout_get_interval(timeout);
311 pollTimeout.tv_sec = localTimeout / 1000;
312 pollTimeout.tv_nsec = (localTimeout % 1000) * 1000000;
314 //prepare handle and callback. new is eval, but there is no other choice because we need the pointer!
315 sh_timerHandle_t* handle = new sh_timerHandle_t;
316 mpListTimerhandles.push_back(handle);
317 IAmShTimerCallBack* buffer = &pDbusTimerCallback;
319 //add the timer to the pollLoop
320 mpSocketHandler->addTimer(pollTimeout, buffer, *handle, timeout);
322 //save the handle with dbus context
323 dbus_timeout_set_data(timeout, handle, NULL);
325 //save timeout in Socket context
327 logInfo("DBusWrapper::addTimeoutDelegate a timeout was added");
331 void CAmDbusWrapper::removeTimeout(DBusTimeout *timeout, void* userData)
333 mpReference = (CAmDbusWrapper*) userData;
334 assert(mpReference!=0);
335 mpReference->removeTimeoutDelegate(timeout, userData);
338 void CAmDbusWrapper::removeTimeoutDelegate(DBusTimeout *timeout, void* userData)
341 //get the pointer to the handle and remove the timer
342 sh_timerHandle_t* handle = (sh_timerHandle_t*) dbus_timeout_get_data(timeout);
343 mpSocketHandler->removeTimer(*handle);
345 //now go throught the timerlist and remove the pointer, free memory
346 std::vector<sh_timerHandle_t*>::iterator it = mpListTimerhandles.begin();
347 for (; it != mpListTimerhandles.end(); ++it)
351 mpListTimerhandles.erase(it);
356 logInfo("DBusWrapper::removeTimeoutDelegate a timeout was removed");
359 void CAmDbusWrapper::toggleTimeout(DBusTimeout *timeout, void* userData)
361 mpReference = (CAmDbusWrapper*) userData;
362 assert(mpReference!=0);
363 mpReference->toggleTimeoutDelegate(timeout, userData);
366 bool am::CAmDbusWrapper::dbusDispatchCallback(const sh_pollHandle_t handle, void *userData)
370 bool returnVal = true;
371 dbus_connection_ref(mpDbusConnection);
372 if (dbus_connection_dispatch(mpDbusConnection) == DBUS_DISPATCH_COMPLETE)
374 dbus_connection_unref(mpDbusConnection);
375 //logInfo("DBusWrapper::dbusDispatchCallback was called");
379 bool am::CAmDbusWrapper::dbusCheckCallback(const sh_pollHandle_t handle, void *userData)
383 bool returnVal = false;
384 dbus_connection_ref(mpDbusConnection);
385 if (dbus_connection_get_dispatch_status(mpDbusConnection) == DBUS_DISPATCH_DATA_REMAINS)
387 dbus_connection_unref(mpDbusConnection);
388 //logInfo("DBusWrapper::dbusCheckCallback was called");
392 void am::CAmDbusWrapper::dbusFireCallback(const pollfd pollfd, const sh_pollHandle_t handle, void *userData)
396 assert(userData!=NULL);
399 if (pollfd.revents & POLLIN)
400 flags |= DBUS_WATCH_READABLE;
401 if (pollfd.revents & POLLOUT)
402 flags |= DBUS_WATCH_WRITABLE;
403 if (pollfd.revents & POLLHUP)
404 flags |= DBUS_WATCH_HANGUP;
405 if (pollfd.revents & POLLERR)
406 flags |= DBUS_WATCH_ERROR;
408 DBusWatch *watch = (DBusWatch*) userData;
410 dbus_connection_ref(mpDbusConnection);
411 dbus_watch_handle(watch, flags);
412 dbus_connection_unref(mpDbusConnection);
413 //logInfo("DBusWrapper::dbusFireCallback was called");
416 void CAmDbusWrapper::toggleTimeoutDelegate(DBusTimeout *timeout, void* userData)
419 //get the pointer to the handle and remove the timer
420 sh_timerHandle_t* handle = (sh_timerHandle_t*) dbus_timeout_get_data(timeout);
423 if (dbus_timeout_get_enabled(timeout))
425 //calculate the timeout in timeval
426 timespec pollTimeout;
427 int localTimeout = dbus_timeout_get_interval(timeout);
428 pollTimeout.tv_sec = localTimeout / 1000;
429 pollTimeout.tv_nsec = (localTimeout % 1000) * 1000000;
430 mpSocketHandler->restartTimer(*handle, pollTimeout);
434 mpSocketHandler->stopTimer(*handle);
436 logInfo("DBusWrapper::toggleTimeoutDelegate was called");
439 void CAmDbusWrapper::dbusTimerCallback(sh_timerHandle_t handle, void *userData)
441 assert(userData!=NULL);
442 if (dbus_timeout_get_enabled((DBusTimeout*) userData))
447 mpSocketHandler->restartTimer(handle, ts);
449 dbus_timeout_handle((DBusTimeout*) userData);
450 logInfo("DBusWrapper::dbusTimerCallback was called");