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