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>
38 //todo: implement time correction if timer was interrupted by call
40 DLT_IMPORT_CONTEXT(AudioManager)
44 SocketHandler::SocketHandler() :
47 mListActiveTimer(), //
49 mLastInsertedHandle(0), //
50 mLastInsertedPollHandle(0), //
51 mRecreatePollfds(true), //
54 mTimeout.tv_nsec = -1;
59 SocketHandler::~SocketHandler()
63 //todo: maybe have some: give me more time returned?
65 * start the block listening for filedescriptors. This is the mainloop.
67 void SocketHandler::start_listenting()
70 std::list<int16_t> hitList;
75 //prepare the signalmask
77 sigemptyset(&sigmask);
78 sigaddset(&sigmask, SIGINT);
79 sigaddset(&sigmask, SIGQUIT);
80 sigaddset(&sigmask, SIGTERM);
81 sigaddset(&sigmask, SIGHUP);
82 sigaddset(&sigmask, SIGQUIT);
84 while (!gDispatchDone)
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)
91 if ((prep = prepIter->prepareCB) != NULL) prep->Call(prepIter->handle, prepIter->userData);
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;
102 //block until something is on a filedescriptor
106 if ((pollStatus = ppoll(&mfdPollingArray.front(), mfdPollingArray.size(), insertTime(buffertime), &sigmask)) < 0)
110 //a signal was received, that means it's time to go...
115 DLT_LOG(AudioManager, DLT_LOG_ERROR, DLT_STRING("SocketHandler::start_listenting ppoll returned with error"), DLT_INT(errno));
121 //sigprocmask (SIG_SETMASK, &mask, &oldmask);
122 if((pollStatus=poll(&mfdPollingArray.front(),mfdPollingArray.size(),timespec2ms(mTimeout)))<0)
127 //a signal was received, that means it's time to go...
128 //todo: add things to do here before going to sleep
131 DLT_LOG(AudioManager, DLT_LOG_ERROR, DLT_STRING("SocketHandler::start_listenting poll returned with error"),DLT_INT(errno));
134 //sigprocmask (SIG_SETMASK, &oldmask, NULL);
137 if (pollStatus != 0) //only check filedescriptors if there was a change
139 //todo: here could be a timer that makes sure naughty plugins return!
141 //get all indexes of the fired events and save them int hitList
143 std::vector<pollfd>::iterator it = mfdPollingArray.begin();
146 it = std::find_if(it, mfdPollingArray.end(), onlyFiredEvents);
147 if (it != mfdPollingArray.end()) hitList.push_back(std::distance(mfdPollingArray.begin(), it++));
149 } while (it != mfdPollingArray.end());
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)
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);
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)
163 shPollCheck* check = NULL;
164 if ((check = mListPoll.at(*hListIt).checkCB) != NULL)
166 if (!check->Call(mListPoll.at(*hListIt).handle, mListPoll.at(*hListIt).userData))
168 hListIt = hitList.erase(hListIt);
173 //stage 3, the ones left need to dispatch, we do this as long as there is something to dispatch..
176 hListIt = hitList.begin();
177 for (; hListIt != hitList.end(); ++hListIt)
179 shPollDispatch *dispatch = NULL;
180 if ((dispatch = mListPoll.at(*hListIt).dispatchCB) != NULL)
182 if (!dispatch->Call(mListPoll.at(*hListIt).handle, mListPoll.at(*hListIt).userData))
184 hListIt = hitList.erase(hListIt);
187 else //there is no dispatch function, so we just remove the file from the list...
189 hListIt = hitList.erase(hListIt);
192 } while (!hitList.empty());
197 //this was a timer event, we need to take care about the timers
206 void SocketHandler::stop_listening()
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
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)
220 if (!fdIsValid(fd)) return E_NON_EXISTENT;
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;
233 //add new data to the list
234 mListPoll.push_back(pollData);
236 mRecreatePollfds = true;
238 handle = pollData.handle;
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
247 am_Error_e SocketHandler::removeFDPoll(const sh_pollHandle_t handle)
249 mListPoll_t::iterator iterator = mListPoll.begin();
251 for (; iterator != mListPoll.end(); ++iterator)
253 if (iterator->handle == handle)
255 iterator = mListPoll.erase(iterator);
256 mRecreatePollfds = true;
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
273 am_Error_e SocketHandler::addTimer(const timespec timeouts, shTimerCallBack*& callback, sh_timerHandle_t& handle, void * userData)
275 assert(!((timeouts.tv_sec==0) && (timeouts.tv_nsec==0)));
276 assert(callback!=NULL);
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;
288 //add timer to the list
289 mListActiveTimer.push_back(timerItem);
290 mListTimer.push_back(timerItem);
292 //very important: sort the list so that the smallest value is front
293 mListActiveTimer.sort(compareCountdown);
294 mTimeout = mListActiveTimer.front().countdown;
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.
303 am_Error_e SocketHandler::removeTimer(const sh_timerHandle_t handle)
307 //stop the current timer
310 std::list<timer_s>::iterator it = mListTimer.begin();
311 for (; it != mListTimer.end(); ++it)
313 if (it->handle == handle)
315 it = mListTimer.erase(it);
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
328 am_Error_e SocketHandler::restartTimer(const sh_timerHandle_t handle, const timespec timeouts)
331 std::list<timer_s>::iterator it = mListTimer.begin();
332 for (; it != mListTimer.end(); ++it)
334 if (it->handle == handle)
341 if (timeouts.tv_nsec != -1 && timeouts.tv_sec != -1)
343 timerItem.timeout = timeouts;
346 mListActiveTimer.push_back(timerItem);
348 //very important: sort the list so that the smallest value is front
349 mListActiveTimer.sort(compareCountdown);
350 mTimeout = mListActiveTimer.front().countdown;
354 am_Error_e SocketHandler::stopTimer(const sh_timerHandle_t handle)
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)
360 if (it->handle == handle)
362 it = mListActiveTimer.erase(it);
363 if (!mListActiveTimer.empty())
365 mTimeout = mListActiveTimer.front().countdown;
369 mTimeout.tv_nsec = -1;
370 mTimeout.tv_sec = -1;
375 return E_NON_EXISTENT;
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
384 am_Error_e SocketHandler::updateEventFlags(const sh_pollHandle_t handle, const int16_t events)
386 mListPoll_t::iterator iterator = mListPoll.begin();
388 for (; iterator != mListPoll.end(); ++iterator)
390 if (iterator->handle == handle)
392 iterator->pollfdValue.events = events;
393 mRecreatePollfds = true;
401 * checks if a filedescriptor is valid
402 * @param fd the filedescriptor
403 * @return true if the fd is valid
405 bool SocketHandler::fdIsValid(const int fd) const
407 return (fcntl(fd, F_GETFL) != -1 || errno != EBADF);
411 * whenever a timer is up, this function needs to be called.
412 * Removes the fired timer, calls the callback and resets mTimeout
414 void SocketHandler::timerUp()
416 //first fire the event
417 mListActiveTimer.front().callback->Call(mListActiveTimer.front().handle, mListActiveTimer.front().userData);
419 //then remove the first timer, the one who fired
420 mListActiveTimer.pop_front();
421 if (!mListActiveTimer.empty())
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;
429 mTimeout.tv_nsec = -1;
430 mTimeout.tv_sec = -1;
437 void SocketHandler::initTimer()
439 if (!mListActiveTimer.empty())
441 mTimeout = mListActiveTimer.front().countdown;
445 mTimeout.tv_nsec = -1;
446 mTimeout.tv_sec = -1;
451 * convert timespec to milliseconds
452 * @param time time in timespec
453 * @return time in milliseconds
455 inline int SocketHandler::timespec2ms(const timespec & time)
457 return (time.tv_nsec == -1 && time.tv_sec == -1) ? -1 : time.tv_sec * 1000 + time.tv_nsec / 1000000;
460 inline timespec* am::SocketHandler::insertTime(timespec& buffertime)
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;
468 * functor to easy substract from each countdown
469 * @param t value to substract from
471 void SocketHandler::SubstractTime::operator ()(timer_s & t) const
474 if ((val = t.countdown.tv_nsec - param.tv_nsec) < 0)
476 t.countdown.tv_nsec = 1000000000 + val;
477 t.countdown.tv_sec--;
481 t.countdown.tv_nsec = val;
483 (t.countdown.tv_sec - param.tv_sec) < 0 ? 0 : (t.countdown.tv_sec -= param.tv_sec);
486 void SocketHandler::CopyPollfd::operator ()(const sh_poll_s & row)
488 pollfd temp = row.pollfdValue;
490 mArray.push_back(temp);