b749fbbc18cff7a73a415ad3ec073b47fe87c8b1
[profile/ivi/audiomanager.git] / AudioManagerDaemon / src / SocketHandler.cpp
1 /**
2 * Copyright (C) 2011, BMW AG
3 *
4 * GeniviAudioMananger AudioManagerDaemon
5 *
6 * \file DBusWrapper.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 "SocketHandler.h"
26 #include <config.h>
27 #include <assert.h>
28 #include <sys/fcntl.h>
29 #include <sys/errno.h>
30 #include <sys/poll.h>
31 #include <algorithm>
32 #include <time.h>
33 #include <features.h>
34 #include <dlt/dlt.h>
35 #include <signal.h>
36
37
38 #include <iostream>
39 //todo: implement time correction if timer was interrupted by call
40
41 DLT_IMPORT_CONTEXT(AudioManager)
42
43 using namespace am;
44
45 SocketHandler::SocketHandler()
46         :mListPoll(),
47          mListTimer(),
48          mListActiveTimer(),
49          mNextTimer(),
50          mLastInsertedHandle(0),
51          mLastInsertedPollHandle(0),
52          mRecreatePollfds(true),
53          mTimeout()
54 {
55         mTimeout.tv_nsec=-1;
56         mTimeout.tv_sec=-1;
57         gDispatchDone=0;
58 }
59
60 SocketHandler::~SocketHandler()
61 {
62 }
63
64
65 //todo: maybe have some: give me more time returned?
66 /**
67  * start the block listening for filedescriptors. This is the mainloop.
68  */
69 void SocketHandler::start_listenting()
70 {
71         int16_t pollStatus;
72         std::list<int16_t>hitList;
73
74         //init the timer
75         initTimer();
76
77         //prepare the signalmask
78         sigset_t sigmask;
79         sigemptyset(&sigmask);
80         sigaddset(&sigmask, SIGINT);
81         sigaddset(&sigmask, SIGQUIT);
82         sigaddset(&sigmask, SIGTERM);
83         sigaddset(&sigmask, SIGHUP);
84         sigaddset(&sigmask, SIGQUIT);
85
86         while (!gDispatchDone)
87         {
88                 //first we go through the registered filedescriptors and check if someone needs preparation:
89                 mListPoll_t::iterator prepIter=mListPoll.begin();
90                 shPollPrepare *prep=NULL;
91                 for(;prepIter!=mListPoll.end();++prepIter)
92                 {
93                         if((prep=prepIter->prepareCB)!=NULL) prep->Call(prepIter->handle,prepIter->userData);
94                 }
95
96                 if(mRecreatePollfds)
97                 {
98                         mfdPollingArray.clear();
99                         //there was a change in the setup, so we need to recreate the fdarray from the list
100                         std::for_each(mListPoll.begin(),mListPoll.end(),CopyPollfd(mfdPollingArray));
101                         mRecreatePollfds=false;
102                 }
103
104                 //block until something is on a filedescriptor
105 #ifdef WITH_PPOLL
106
107                 timespec buffertime;
108                 if((pollStatus=ppoll(&mfdPollingArray.front(),mfdPollingArray.size(),insertTime(buffertime),&sigmask))<0)
109                 {
110                         if(errno==EINTR)
111                         {
112                                 //a signal was received, that means it's time to go...
113                                 pollStatus=0;
114                         }
115                         else
116                         {
117                                 DLT_LOG(AudioManager, DLT_LOG_ERROR, DLT_STRING("SocketHandler::start_listenting ppoll returned with error"),DLT_INT(errno));
118                                 exit(0);
119                         }
120                 }
121
122 #else
123                 //sigprocmask (SIG_SETMASK, &mask, &oldmask);
124                 if((pollStatus=poll(&mfdPollingArray.front(),mfdPollingArray.size(),timespec2ms(mTimeout)))<0)
125                 {
126
127                         if(errno==EINTR)
128                         {
129                                 //a signal was received, that means it's time to go...
130                                 //todo: add things to do here before going to sleep
131                         exit(0);
132                         }
133                         DLT_LOG(AudioManager, DLT_LOG_ERROR, DLT_STRING("SocketHandler::start_listenting poll returned with error"),DLT_INT(errno));
134                         exit(0);
135                 }
136                 //sigprocmask (SIG_SETMASK, &oldmask, NULL);
137 #endif
138
139                 if (pollStatus!=0) //only check filedescriptors if there was a change
140                 {
141                         //todo: here could be a timer that makes sure naughty plugins return!
142
143                         //get all indexes of the fired events and save them int hitList
144                         hitList.clear();
145                         std::vector<pollfd>::iterator it=mfdPollingArray.begin();
146                         do
147                         {
148                                 it=std::find_if(it,mfdPollingArray.end(),onlyFiredEvents);
149                                 if (it!=mfdPollingArray.end()) hitList.push_back(std::distance(mfdPollingArray.begin(), it++));
150
151                         } while (it!=mfdPollingArray.end());
152
153                         //stage 1, call firedCB for all matched events, but only if callback is not zero!
154                         std::list<int16_t>::iterator hListIt=hitList.begin();
155                         for(;hListIt!=hitList.end();++hListIt)
156                         {
157                                 shPollFired* fire=NULL;
158                                 if ((fire=mListPoll.at(*hListIt).firedCB)!=NULL) fire->Call(mfdPollingArray.at(*hListIt),mListPoll.at(*hListIt).handle,mListPoll.at(*hListIt).userData);
159                         }
160
161                         //stage 2, lets ask around if some dispatching is necessary, if not, they are taken from the hitlist
162                         hListIt=hitList.begin();
163                         for(;hListIt!=hitList.end();++hListIt)
164                         {
165                                 shPollCheck* check=NULL;
166                                 if ((check=mListPoll.at(*hListIt).checkCB)!=NULL)
167                                 {
168                                         if (!check->Call(mListPoll.at(*hListIt).handle,mListPoll.at(*hListIt).userData))
169                                         {
170                                                 hListIt=hitList.erase(hListIt);
171                                         }
172                                 }
173                         }
174
175                         //stage 3, the ones left need to dispatch, we do this as long as there is something to dispatch..
176                         do
177                         {
178                                 hListIt=hitList.begin();
179                                 for(;hListIt!=hitList.end();++hListIt)
180                                 {
181                                         shPollDispatch *dispatch=NULL;
182                                         if((dispatch=mListPoll.at(*hListIt).dispatchCB)!=NULL)
183                                         {
184                                                 if (!dispatch->Call(mListPoll.at(*hListIt).handle,mListPoll.at(*hListIt).userData))
185                                                 {
186                                                         hListIt=hitList.erase(hListIt);
187                                                 }
188                                         }
189                                         else //there is no dispatch function, so we just remove the file from the list...
190                                         {
191                                                 hListIt=hitList.erase(hListIt);
192                                         }
193                                 }
194                         } while (!hitList.empty());
195
196                 }
197                 else //Timerevent
198                 {
199                         //this was a timer event, we need to take care about the timers
200                         timerUp();
201                 }
202         }
203 }
204
205 /**
206  * exits the loop
207  */
208 void SocketHandler::stop_listening()
209 {
210         gDispatchDone=1;
211 }
212
213 /**
214  * Adds a filedescriptor to the polling loop
215  * @param fd this is a valid filedescriptor
216  * @param event the event flags
217  * @param callback the callback that shall be called if the filedescriptor poll succeeded
218  * @return E_OK if the descriptor was added, E_NON_EXISTENT if the fd is not valid
219  */
220 am_Error_e SocketHandler::addFDPoll(const int fd,const int16_t event, shPollPrepare *prepare,shPollFired *fired,shPollCheck *check,shPollDispatch *dispatch, void* userData,sh_pollHandle_t& handle)
221 {
222         if (!fdIsValid(fd)) return E_NON_EXISTENT;
223
224         sh_poll_s pollData;
225         pollData.pollfdValue.fd=fd;
226         pollData.handle=++mLastInsertedPollHandle;
227         pollData.pollfdValue.events=event;
228         pollData.pollfdValue.revents=0;
229         pollData.userData=userData;
230         pollData.prepareCB=prepare;
231         pollData.firedCB=fired;
232         pollData.checkCB=check;
233         pollData.dispatchCB=dispatch;
234
235         //add new data to the list
236         mListPoll.push_back(pollData);
237
238         mRecreatePollfds=true;
239
240         handle=pollData.handle;
241         return E_OK;
242 }
243
244 /**
245  * removes a filedescriptor from the poll loop
246  * @param fd the filedescriptor to be removed
247  * @return E_OK in case of sucess, E_NON_EXISTENT or E_UNKNOWN if the fd in not registered
248  */
249 am_Error_e SocketHandler::removeFDPoll(const sh_pollHandle_t handle)
250 {
251         mListPoll_t::iterator iterator=mListPoll.begin();
252
253         for (;iterator!=mListPoll.end();++iterator)
254         {
255                 if(iterator->handle==handle)
256                 {
257                         iterator=mListPoll.erase(iterator);
258                         mRecreatePollfds=true;
259                         return E_OK;
260                 }
261         }
262         return E_UNKNOWN;
263 }
264
265 /**
266  * adds a timer to the list of timers. The callback will be fired when the timer is up.
267  * This is not a high precise timer, it is very coarse. It is meant to be used for timeouts when waiting
268  * for an answer via a filedescriptor.
269  * One time timer. If you need again a timer, you need to add a new timer in the callback of the old one.
270  * @param timeouts time until the callback is fired
271  * @param callback the callback
272  * @param handle the handle that is created for the timer is returned. Can be used to remove the timer
273  * @return E_OK in case of success
274  */
275 am_Error_e SocketHandler::addTimer(const timespec timeouts,shTimerCallBack*& callback,sh_timerHandle_t& handle, void * userData)
276 {
277         assert(!((timeouts.tv_sec==0) && (timeouts.tv_nsec==0)));
278         assert(callback!=NULL);
279
280         timer_s timerItem;
281
282         //create a new handle for the timer
283         handle=++mLastInsertedHandle;  //todo: overflow ruling !
284         timerItem.handle=handle;
285         timerItem.countdown=timeouts;
286         timerItem.timeout=timeouts;
287         timerItem.callback=callback;
288         timerItem.userData=userData;
289
290         //add timer to the list
291         mListActiveTimer.push_back(timerItem);
292         mListTimer.push_back(timerItem);
293
294         //very important: sort the list so that the smallest value is front
295         mListActiveTimer.sort(compareCountdown);
296         mTimeout=mListActiveTimer.front().countdown;
297         return E_OK;
298 }
299
300 /**
301  * removes a timer from the list of timers
302  * @param handle the handle to the timer
303  * @return E_OK in case of success, E_UNKNOWN if timer was not found.
304  */
305 am_Error_e SocketHandler::removeTimer(const sh_timerHandle_t handle)
306 {
307         assert(handle!=0);
308
309         //stop the current timer
310         stopTimer(handle);
311
312         std::list<timer_s>::iterator it=mListTimer.begin();
313         for(;it!=mListTimer.end();++it)
314         {
315                 if(it->handle==handle)
316                 {
317                         it=mListTimer.erase(it);
318                         return E_OK;
319                 }
320         }
321         return E_UNKNOWN;
322 }
323
324 /**
325  * restarts a timer and updates with a new interval
326  * @param handle handle to the timer
327  * @param timeouts new timout time
328  * @return E_OK on success, E_NON_EXISTENT if the handle was not found
329  */
330 am_Error_e SocketHandler::restartTimer(const sh_timerHandle_t handle, const timespec timeouts)
331 {
332         timer_s timerItem;
333         std::list<timer_s>::iterator it=mListTimer.begin();
334         for(;it!=mListTimer.end();++it)
335         {
336                 if (it->handle==handle)
337                 {
338                         timerItem=*it;
339                         break;
340                 }
341         }
342
343         if (timeouts.tv_nsec!=-1 && timeouts.tv_sec!=-1)
344         {
345                 timerItem.timeout=timeouts;
346         }
347
348         mListActiveTimer.push_back(timerItem);
349
350         //very important: sort the list so that the smallest value is front
351         mListActiveTimer.sort(compareCountdown);
352         mTimeout=mListActiveTimer.front().countdown;
353         return E_OK;
354 }
355
356 am_Error_e SocketHandler::stopTimer(const sh_timerHandle_t handle)
357 {
358         //go through the list and remove the timer with the handle
359         std::list<timer_s>::iterator it=mListActiveTimer.begin();
360         for(;it!=mListActiveTimer.end();++it)
361         {
362                 if(it->handle==handle)
363                 {
364                         it=mListActiveTimer.erase(it);
365                         if (!mListActiveTimer.empty())
366                         {
367                                 mTimeout=mListActiveTimer.front().countdown;
368                         }
369                         else
370                         {
371                                 mTimeout.tv_nsec=-1;
372                                 mTimeout.tv_sec=-1;
373                         }
374                         return E_OK;
375                 }
376         }
377         return E_NON_EXISTENT;
378 }
379
380 /**
381  * updates the eventFlags of a poll
382  * @param fd the filedescriptor of the poll
383  * @param event the event flags
384  * @return E_OK on succsess, E_NON_EXISTENT if fd was not found
385  */
386 am_Error_e SocketHandler::updateEventFlags(const sh_pollHandle_t handle, const int16_t  events)
387 {
388         mListPoll_t::iterator iterator=mListPoll.begin();
389
390         for (;iterator!=mListPoll.end();++iterator)
391         {
392                 if(iterator->handle==handle)
393                 {
394                         iterator->pollfdValue.events=events;
395                         mRecreatePollfds=true;
396                         return E_OK;
397                 }
398         }
399         return E_UNKNOWN;
400 }
401
402 /**
403  * checks if a filedescriptor is valid
404  * @param fd the filedescriptor
405  * @return true if the fd is valid
406  */
407 bool SocketHandler::fdIsValid(const int fd) const
408 {
409         return (fcntl(fd, F_GETFL) != -1 || errno != EBADF);
410 }
411
412 /**
413  * whenever a timer is up, this function needs to be called.
414  * Removes the fired timer, calls the callback and resets mTimeout
415  */
416 void SocketHandler::timerUp()
417 {
418         //first fire the event
419         mListActiveTimer.front().callback->Call(mListActiveTimer.front().handle,mListActiveTimer.front().userData);
420
421         //then remove the first timer, the one who fired
422         mListActiveTimer.pop_front();
423         if(!mListActiveTimer.empty())
424         {
425                 //substract the old value from all timers in the list
426                 std::for_each(mListActiveTimer.begin(),mListActiveTimer.end(),SubstractTime(mTimeout));
427                 mTimeout=mListActiveTimer.front().countdown;
428         }
429         else
430         {
431                 mTimeout.tv_nsec=-1;
432                 mTimeout.tv_sec=-1;
433         }
434 }
435
436 /**
437  * init the timers
438  */
439 void SocketHandler::initTimer()
440 {
441         if(!mListActiveTimer.empty())
442         {
443                 mTimeout=mListActiveTimer.front().countdown;
444         }
445         else
446         {
447                 mTimeout.tv_nsec=-1;
448                 mTimeout.tv_sec=-1;
449         }
450 }
451
452
453 /**
454 * convert timespec to milliseconds
455 * @param time time in timespec
456 * @return time in milliseconds
457 */
458 inline int SocketHandler::timespec2ms(const timespec & time)
459 {
460         return (time.tv_nsec == -1 && time.tv_sec == -1) ? -1 : time.tv_sec * 1000 + time.tv_nsec / 1000000;
461 }
462
463 inline timespec* am::SocketHandler::insertTime(timespec& buffertime)
464 {
465         buffertime.tv_nsec=mTimeout.tv_nsec;
466         buffertime.tv_sec=mTimeout.tv_sec;
467         return (mTimeout.tv_nsec == -1 && mTimeout.tv_sec == -1) ? NULL : &buffertime;
468 }
469
470 /**
471 * functor to easy substract from each countdown
472 * @param t value to substract from
473 */
474 void SocketHandler::SubstractTime::operator ()(timer_s & t) const
475 {
476         int val = 0;
477         if((val = t.countdown.tv_nsec - param.tv_nsec) < 0){
478                 t.countdown.tv_nsec = 1000000000 + val;
479                 t.countdown.tv_sec--;
480         }else{
481                 t.countdown.tv_nsec = val;
482         }
483         (t.countdown.tv_sec - param.tv_sec) < 0 ? 0 : (t.countdown.tv_sec -= param.tv_sec);
484 }
485
486 void SocketHandler::CopyPollfd::operator ()(const sh_poll_s & row)
487 {
488         pollfd temp=row.pollfdValue;
489         temp.revents=0;
490         mArray.push_back(temp);
491 }
492
493
494
495
496
497