2 * Copyright (C) 2011, BMW AG
4 * GeniviAudioMananger AudioManagerDaemon
6 * \file DBusWrapper.cpp
8 * \date 20-Oct-2011 3:42:04 PM
9 * \author Christian Mueller (christian.ei.mueller@bmw.de)
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
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.
25 #include "SocketHandler.h"
28 #include <sys/fcntl.h>
29 #include <sys/errno.h>
35 #include "DLTWrapper.h"
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
42 SocketHandler::SocketHandler() :
45 mListActiveTimer(), //
47 mLastInsertedHandle(0), //
48 mLastInsertedPollHandle(0), //
49 mRecreatePollfds(true), //
52 mTimeout.tv_nsec = -1;
57 SocketHandler::~SocketHandler()
61 //todo: maybe have some: give me more time returned?
63 * start the block listening for filedescriptors. This is the mainloop.
65 void SocketHandler::start_listenting()
68 std::list<int16_t> hitList;
73 //prepare the signalmask
75 sigemptyset(&sigmask);
76 sigaddset(&sigmask, SIGINT);
77 sigaddset(&sigmask, SIGQUIT);
78 sigaddset(&sigmask, SIGTERM);
79 sigaddset(&sigmask, SIGHUP);
80 sigaddset(&sigmask, SIGQUIT);
82 while (!gDispatchDone)
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)
89 if ((prep = prepIter->prepareCB) != NULL)
90 prep->Call(prepIter->handle, prepIter->userData);
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;
101 //block until something is on a filedescriptor
105 if ((pollStatus = ppoll(&mfdPollingArray[0], mfdPollingArray.size(), insertTime(buffertime), &sigmask)) < 0)
109 //a signal was received, that means it's time to go...
114 logError("SocketHandler::start_listenting ppoll returned with error", errno);
120 //sigprocmask (SIG_SETMASK, &mask, &oldmask);
121 if((pollStatus=poll(&mfdPollingArray[0],mfdPollingArray.size(),timespec2ms(mTimeout)))<0)
126 //a signal was received, that means it's time to go...
127 //todo: add things to do here before going to sleep
130 logError("SocketHandler::start_listenting poll returned with error",errno);
133 //sigprocmask (SIG_SETMASK, &oldmask, NULL);
136 if (pollStatus != 0) //only check filedescriptors if there was a change
138 //todo: here could be a timer that makes sure naughty plugins return!
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);
143 //get all indexes of the fired events and save them int hitList
145 std::vector<pollfd>::iterator it = mfdPollingArray.begin();
148 it = std::find_if(it, mfdPollingArray.end(), onlyFiredEvents);
149 if (it != mfdPollingArray.end())
150 hitList.push_back(std::distance(mfdPollingArray.begin(), it++));
152 } while (it != mfdPollingArray.end());
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)
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);
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)
167 shPollCheck* check = NULL;
168 if ((check = listPoll.at(*hListIt).checkCB) != NULL)
170 if (!check->Call(listPoll.at(*hListIt).handle, listPoll.at(*hListIt).userData))
172 hListIt = hitList.erase(hListIt);
177 //stage 3, the ones left need to dispatch, we do this as long as there is something to dispatch..
180 hListIt = hitList.begin();
181 for (; hListIt != hitList.end(); ++hListIt)
183 shPollDispatch *dispatch = NULL;
184 if ((dispatch = listPoll.at(*hListIt).dispatchCB) != NULL)
186 if (!dispatch->Call(listPoll.at(*hListIt).handle, listPoll.at(*hListIt).userData))
188 hListIt = hitList.erase(hListIt);
191 else //there is no dispatch function, so we just remove the file from the list...
193 hListIt = hitList.erase(hListIt);
196 } while (!hitList.empty());
201 //this was a timer event, we need to take care about the timers
210 void SocketHandler::stop_listening()
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
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)
226 return E_NON_EXISTENT;
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;
239 //add new data to the list
240 mListPoll.push_back(pollData);
242 mRecreatePollfds = true;
244 handle = pollData.handle;
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
253 am_Error_e SocketHandler::removeFDPoll(const sh_pollHandle_t handle)
255 mListPoll_t::iterator iterator = mListPoll.begin();
257 for (; iterator != mListPoll.end(); ++iterator)
259 if (iterator->handle == handle)
261 iterator = mListPoll.erase(iterator);
262 mRecreatePollfds = true;
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
279 am_Error_e SocketHandler::addTimer(const timespec timeouts, shTimerCallBack*& callback, sh_timerHandle_t& handle, void * userData)
281 assert(!((timeouts.tv_sec==0) && (timeouts.tv_nsec==0)));
282 assert(callback!=NULL);
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;
294 //add timer to the list
295 mListActiveTimer.push_back(timerItem);
296 mListTimer.push_back(timerItem);
298 //very important: sort the list so that the smallest value is front
299 mListActiveTimer.sort(compareCountdown);
300 mTimeout = mListActiveTimer.front().countdown;
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.
309 am_Error_e SocketHandler::removeTimer(const sh_timerHandle_t handle)
313 //stop the current timer
316 std::list<timer_s>::iterator it = mListTimer.begin();
317 for (; it != mListTimer.end(); ++it)
319 if (it->handle == handle)
321 it = mListTimer.erase(it);
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
334 am_Error_e SocketHandler::restartTimer(const sh_timerHandle_t handle, const timespec timeouts)
337 std::list<timer_s>::iterator it = mListTimer.begin();
338 for (; it != mListTimer.end(); ++it)
340 if (it->handle == handle)
347 if (timeouts.tv_nsec != -1 && timeouts.tv_sec != -1)
349 timerItem.timeout = timeouts;
352 mListActiveTimer.push_back(timerItem);
354 //very important: sort the list so that the smallest value is front
355 mListActiveTimer.sort(compareCountdown);
356 mTimeout = mListActiveTimer.front().countdown;
360 am_Error_e SocketHandler::stopTimer(const sh_timerHandle_t handle)
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)
366 if (it->handle == handle)
368 it = mListActiveTimer.erase(it);
369 if (!mListActiveTimer.empty())
371 mTimeout = mListActiveTimer.front().countdown;
375 mTimeout.tv_nsec = -1;
376 mTimeout.tv_sec = -1;
381 return E_NON_EXISTENT;
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
390 am_Error_e SocketHandler::updateEventFlags(const sh_pollHandle_t handle, const short events)
392 mListPoll_t::iterator iterator = mListPoll.begin();
394 for (; iterator != mListPoll.end(); ++iterator)
396 if (iterator->handle == handle)
398 iterator->pollfdValue.events = events;
399 mRecreatePollfds = true;
407 * checks if a filedescriptor is valid
408 * @param fd the filedescriptor
409 * @return true if the fd is valid
411 bool SocketHandler::fdIsValid(const int fd) const
413 return (fcntl(fd, F_GETFL) != -1 || errno != EBADF);
417 * whenever a timer is up, this function needs to be called.
418 * Removes the fired timer, calls the callback and resets mTimeout
420 void SocketHandler::timerUp()
422 //first fire the event
423 mListActiveTimer.front().callback->Call(mListActiveTimer.front().handle, mListActiveTimer.front().userData);
425 //then remove the first timer, the one who fired
426 mListActiveTimer.pop_front();
427 if (!mListActiveTimer.empty())
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;
435 mTimeout.tv_nsec = -1;
436 mTimeout.tv_sec = -1;
443 void SocketHandler::initTimer()
445 if (!mListActiveTimer.empty())
447 mTimeout = mListActiveTimer.front().countdown;
451 mTimeout.tv_nsec = -1;
452 mTimeout.tv_sec = -1;
457 * convert timespec to milliseconds
458 * @param time time in timespec
459 * @return time in milliseconds
461 inline int SocketHandler::timespec2ms(const timespec & time)
463 return (time.tv_nsec == -1 && time.tv_sec == -1) ? -1 : time.tv_sec * 1000 + time.tv_nsec / 1000000;
466 inline timespec* am::SocketHandler::insertTime(timespec& buffertime)
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;
474 * functor to easy substract from each countdown
475 * @param t value to substract from
477 void SocketHandler::SubstractTime::operator ()(timer_s & t) const
480 if ((val = t.countdown.tv_nsec - param.tv_nsec) < 0)
482 t.countdown.tv_nsec = 1000000000 + val;
483 t.countdown.tv_sec--;
487 t.countdown.tv_nsec = val;
489 (t.countdown.tv_sec - param.tv_sec) < 0 ? 0 : (t.countdown.tv_sec -= param.tv_sec);
492 void SocketHandler::CopyPollfd::operator ()(const sh_poll_s & row)
494 pollfd temp = row.pollfdValue;
496 mArray.push_back(temp);