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
41 SocketHandler::SocketHandler() :
44 mListActiveTimer(), //
46 mLastInsertedHandle(0), //
47 mLastInsertedPollHandle(0), //
48 mRecreatePollfds(true), //
51 mTimeout.tv_nsec = -1;
56 SocketHandler::~SocketHandler()
60 //todo: maybe have some: give me more time returned?
62 * start the block listening for filedescriptors. This is the mainloop.
64 void SocketHandler::start_listenting()
67 std::list<int16_t> hitList;
72 //prepare the signalmask
74 sigemptyset(&sigmask);
75 sigaddset(&sigmask, SIGINT);
76 sigaddset(&sigmask, SIGQUIT);
77 sigaddset(&sigmask, SIGTERM);
78 sigaddset(&sigmask, SIGHUP);
79 sigaddset(&sigmask, SIGQUIT);
81 while (!gDispatchDone)
83 //first we go through the registered filedescriptors and check if someone needs preparation:
84 mListPoll_t::iterator prepIter = mListPoll.begin();
85 shPollPrepare *prep = NULL;
86 for (; prepIter != mListPoll.end(); ++prepIter)
88 if ((prep = prepIter->prepareCB) != NULL) prep->Call(prepIter->handle, prepIter->userData);
93 mfdPollingArray.clear();
94 //there was a change in the setup, so we need to recreate the fdarray from the list
95 std::for_each(mListPoll.begin(), mListPoll.end(), CopyPollfd(mfdPollingArray));
96 mRecreatePollfds = false;
99 //block until something is on a filedescriptor
103 if ((pollStatus = ppoll(&mfdPollingArray.front(), mfdPollingArray.size(), insertTime(buffertime), &sigmask)) < 0)
107 //a signal was received, that means it's time to go...
112 logError("SocketHandler::start_listenting ppoll returned with error",errno);
118 //sigprocmask (SIG_SETMASK, &mask, &oldmask);
119 if((pollStatus=poll(&mfdPollingArray.front(),mfdPollingArray.size(),timespec2ms(mTimeout)))<0)
124 //a signal was received, that means it's time to go...
125 //todo: add things to do here before going to sleep
128 logError("SocketHandler::start_listenting poll returned with error",errno);
131 //sigprocmask (SIG_SETMASK, &oldmask, NULL);
134 if (pollStatus != 0) //only check filedescriptors if there was a change
136 //todo: here could be a timer that makes sure naughty plugins return!
138 //get all indexes of the fired events and save them int hitList
140 std::vector<pollfd>::iterator it = mfdPollingArray.begin();
143 it = std::find_if(it, mfdPollingArray.end(), onlyFiredEvents);
144 if (it != mfdPollingArray.end()) hitList.push_back(std::distance(mfdPollingArray.begin(), it++));
146 } while (it != mfdPollingArray.end());
148 //stage 1, call firedCB for all matched events, but only if callback is not zero!
149 std::list<int16_t>::iterator hListIt = hitList.begin();
150 for (; hListIt != hitList.end(); ++hListIt)
152 shPollFired* fire = NULL;
153 if ((fire = mListPoll.at(*hListIt).firedCB) != NULL) fire->Call(mfdPollingArray.at(*hListIt), mListPoll.at(*hListIt).handle, mListPoll.at(*hListIt).userData);
156 //stage 2, lets ask around if some dispatching is necessary, if not, they are taken from the hitlist
157 hListIt = hitList.begin();
158 for (; hListIt != hitList.end(); ++hListIt)
160 shPollCheck* check = NULL;
161 if ((check = mListPoll.at(*hListIt).checkCB) != NULL)
163 if (!check->Call(mListPoll.at(*hListIt).handle, mListPoll.at(*hListIt).userData))
165 hListIt = hitList.erase(hListIt);
170 //stage 3, the ones left need to dispatch, we do this as long as there is something to dispatch..
173 hListIt = hitList.begin();
174 for (; hListIt != hitList.end(); ++hListIt)
176 shPollDispatch *dispatch = NULL;
177 if ((dispatch = mListPoll.at(*hListIt).dispatchCB) != NULL)
179 if (!dispatch->Call(mListPoll.at(*hListIt).handle, mListPoll.at(*hListIt).userData))
181 hListIt = hitList.erase(hListIt);
184 else //there is no dispatch function, so we just remove the file from the list...
186 hListIt = hitList.erase(hListIt);
189 } while (!hitList.empty());
194 //this was a timer event, we need to take care about the timers
203 void SocketHandler::stop_listening()
209 * Adds a filedescriptor to the polling loop
210 * @param fd this is a valid filedescriptor
211 * @param event the event flags
212 * @param callback the callback that shall be called if the filedescriptor poll succeeded
213 * @return E_OK if the descriptor was added, E_NON_EXISTENT if the fd is not valid
215 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)
217 if (!fdIsValid(fd)) return E_NON_EXISTENT;
220 pollData.pollfdValue.fd = fd;
221 pollData.handle = ++mLastInsertedPollHandle;
222 pollData.pollfdValue.events = event;
223 pollData.pollfdValue.revents = 0;
224 pollData.userData = userData;
225 pollData.prepareCB = prepare;
226 pollData.firedCB = fired;
227 pollData.checkCB = check;
228 pollData.dispatchCB = dispatch;
230 //add new data to the list
231 mListPoll.push_back(pollData);
233 mRecreatePollfds = true;
235 handle = pollData.handle;
240 * removes a filedescriptor from the poll loop
241 * @param fd the filedescriptor to be removed
242 * @return E_OK in case of sucess, E_NON_EXISTENT or E_UNKNOWN if the fd in not registered
244 am_Error_e SocketHandler::removeFDPoll(const sh_pollHandle_t handle)
246 mListPoll_t::iterator iterator = mListPoll.begin();
248 for (; iterator != mListPoll.end(); ++iterator)
250 if (iterator->handle == handle)
252 iterator = mListPoll.erase(iterator);
253 mRecreatePollfds = true;
261 * adds a timer to the list of timers. The callback will be fired when the timer is up.
262 * This is not a high precise timer, it is very coarse. It is meant to be used for timeouts when waiting
263 * for an answer via a filedescriptor.
264 * One time timer. If you need again a timer, you need to add a new timer in the callback of the old one.
265 * @param timeouts time until the callback is fired
266 * @param callback the callback
267 * @param handle the handle that is created for the timer is returned. Can be used to remove the timer
268 * @return E_OK in case of success
270 am_Error_e SocketHandler::addTimer(const timespec timeouts, shTimerCallBack*& callback, sh_timerHandle_t& handle, void * userData)
272 assert(!((timeouts.tv_sec==0) && (timeouts.tv_nsec==0)));
273 assert(callback!=NULL);
277 //create a new handle for the timer
278 handle = ++mLastInsertedHandle; //todo: overflow ruling !
279 timerItem.handle = handle;
280 timerItem.countdown = timeouts;
281 timerItem.timeout = timeouts;
282 timerItem.callback = callback;
283 timerItem.userData = userData;
285 //add timer to the list
286 mListActiveTimer.push_back(timerItem);
287 mListTimer.push_back(timerItem);
289 //very important: sort the list so that the smallest value is front
290 mListActiveTimer.sort(compareCountdown);
291 mTimeout = mListActiveTimer.front().countdown;
296 * removes a timer from the list of timers
297 * @param handle the handle to the timer
298 * @return E_OK in case of success, E_UNKNOWN if timer was not found.
300 am_Error_e SocketHandler::removeTimer(const sh_timerHandle_t handle)
304 //stop the current timer
307 std::list<timer_s>::iterator it = mListTimer.begin();
308 for (; it != mListTimer.end(); ++it)
310 if (it->handle == handle)
312 it = mListTimer.erase(it);
320 * restarts a timer and updates with a new interval
321 * @param handle handle to the timer
322 * @param timeouts new timout time
323 * @return E_OK on success, E_NON_EXISTENT if the handle was not found
325 am_Error_e SocketHandler::restartTimer(const sh_timerHandle_t handle, const timespec timeouts)
328 std::list<timer_s>::iterator it = mListTimer.begin();
329 for (; it != mListTimer.end(); ++it)
331 if (it->handle == handle)
338 if (timeouts.tv_nsec != -1 && timeouts.tv_sec != -1)
340 timerItem.timeout = timeouts;
343 mListActiveTimer.push_back(timerItem);
345 //very important: sort the list so that the smallest value is front
346 mListActiveTimer.sort(compareCountdown);
347 mTimeout = mListActiveTimer.front().countdown;
351 am_Error_e SocketHandler::stopTimer(const sh_timerHandle_t handle)
353 //go through the list and remove the timer with the handle
354 std::list<timer_s>::iterator it = mListActiveTimer.begin();
355 for (; it != mListActiveTimer.end(); ++it)
357 if (it->handle == handle)
359 it = mListActiveTimer.erase(it);
360 if (!mListActiveTimer.empty())
362 mTimeout = mListActiveTimer.front().countdown;
366 mTimeout.tv_nsec = -1;
367 mTimeout.tv_sec = -1;
372 return E_NON_EXISTENT;
376 * updates the eventFlags of a poll
377 * @param fd the filedescriptor of the poll
378 * @param event the event flags
379 * @return E_OK on succsess, E_NON_EXISTENT if fd was not found
381 am_Error_e SocketHandler::updateEventFlags(const sh_pollHandle_t handle, const int16_t events)
383 mListPoll_t::iterator iterator = mListPoll.begin();
385 for (; iterator != mListPoll.end(); ++iterator)
387 if (iterator->handle == handle)
389 iterator->pollfdValue.events = events;
390 mRecreatePollfds = true;
398 * checks if a filedescriptor is valid
399 * @param fd the filedescriptor
400 * @return true if the fd is valid
402 bool SocketHandler::fdIsValid(const int fd) const
404 return (fcntl(fd, F_GETFL) != -1 || errno != EBADF);
408 * whenever a timer is up, this function needs to be called.
409 * Removes the fired timer, calls the callback and resets mTimeout
411 void SocketHandler::timerUp()
413 //first fire the event
414 mListActiveTimer.front().callback->Call(mListActiveTimer.front().handle, mListActiveTimer.front().userData);
416 //then remove the first timer, the one who fired
417 mListActiveTimer.pop_front();
418 if (!mListActiveTimer.empty())
420 //substract the old value from all timers in the list
421 std::for_each(mListActiveTimer.begin(), mListActiveTimer.end(), SubstractTime(mTimeout));
422 mTimeout = mListActiveTimer.front().countdown;
426 mTimeout.tv_nsec = -1;
427 mTimeout.tv_sec = -1;
434 void SocketHandler::initTimer()
436 if (!mListActiveTimer.empty())
438 mTimeout = mListActiveTimer.front().countdown;
442 mTimeout.tv_nsec = -1;
443 mTimeout.tv_sec = -1;
448 * convert timespec to milliseconds
449 * @param time time in timespec
450 * @return time in milliseconds
452 inline int SocketHandler::timespec2ms(const timespec & time)
454 return (time.tv_nsec == -1 && time.tv_sec == -1) ? -1 : time.tv_sec * 1000 + time.tv_nsec / 1000000;
457 inline timespec* am::SocketHandler::insertTime(timespec& buffertime)
459 buffertime.tv_nsec = mTimeout.tv_nsec;
460 buffertime.tv_sec = mTimeout.tv_sec;
461 return (mTimeout.tv_nsec == -1 && mTimeout.tv_sec == -1) ? NULL : &buffertime;
465 * functor to easy substract from each countdown
466 * @param t value to substract from
468 void SocketHandler::SubstractTime::operator ()(timer_s & t) const
471 if ((val = t.countdown.tv_nsec - param.tv_nsec) < 0)
473 t.countdown.tv_nsec = 1000000000 + val;
474 t.countdown.tv_sec--;
478 t.countdown.tv_nsec = val;
480 (t.countdown.tv_sec - param.tv_sec) < 0 ? 0 : (t.countdown.tv_sec -= param.tv_sec);
483 void SocketHandler::CopyPollfd::operator ()(const sh_poll_s & row)
485 pollfd temp = row.pollfdValue;
487 mArray.push_back(temp);