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