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