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"
27 #include <sys/fcntl.h>
28 #include <sys/errno.h>
34 //todo: implement ppoll
35 //todo: signal handling here
36 //todo: implement time correction if timer was interrupted by call
38 #include <iostream> //todo remove
42 SocketHandler::SocketHandler()
47 mLastInsertedHandle(0),
48 mLastInsertedPollHandle(0),
50 mRecreatePollfds(true)
56 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;
75 //first we go through the registered filedescriptors and check if someone needs preparation:
76 mListPoll_t::iterator prepIter=mListPoll.begin();
77 shPollPrepare *prep=NULL;
78 for(;prepIter!=mListPoll.end();++prepIter)
80 if((prep=prepIter->prepareCB)!=NULL) prep->Call(prepIter->handle,prepIter->userData);
85 mfdPollingArray.clear();
86 //there was a change in the setup, so we need to recreate the fdarray from the list
87 std::for_each(mListPoll.begin(),mListPoll.end(),CopyPollfd(mfdPollingArray));
88 mRecreatePollfds=false;
91 //block until something is on a filedescriptor
92 if((pollStatus=poll(&mfdPollingArray.front(),mfdPollingArray.size(),timespec2ms(mTimeout)))==-1)
94 //todo enter DLT message here;
97 if (pollStatus!=0) //only check filedescriptors if there was a change
99 //todo: here could be a timer that makes sure naughty plugins return!
101 //get all indexes of the fired events and save them int hitList
103 std::vector<pollfd>::iterator it=mfdPollingArray.begin();
106 it=std::find_if(it,mfdPollingArray.end(),onlyFiredEvents);
107 if (it!=mfdPollingArray.end()) hitList.push_back(std::distance(mfdPollingArray.begin(), it++));
109 } while (it!=mfdPollingArray.end());
111 //stage 1, call firedCB for all matched events, but only if callback is not zero!
112 std::list<int16_t>::iterator hListIt=hitList.begin();
113 for(;hListIt!=hitList.end();++hListIt)
115 shPollFired* fire=NULL;
116 if ((fire=mListPoll.at(*hListIt).firedCB)!=NULL) fire->Call(mfdPollingArray.at(*hListIt),mListPoll.at(*hListIt).handle,mListPoll.at(*hListIt).userData);
119 //stage 2, lets ask around if some dispatching is necessary, if not, they are taken from the hitlist
120 hListIt=hitList.begin();
121 for(;hListIt!=hitList.end();++hListIt)
123 shPollCheck* check=NULL;
124 if ((check=mListPoll.at(*hListIt).checkCB)!=NULL)
126 if (!check->Call(mListPoll.at(*hListIt).handle,mListPoll.at(*hListIt).userData))
128 hListIt=hitList.erase(hListIt);
133 //stage 3, the ones left need to dispatch, we do this as long as there is something to dispatch..
136 hListIt=hitList.begin();
137 for(;hListIt!=hitList.end();++hListIt)
139 shPollDispatch *dispatch=NULL;
140 if((dispatch=mListPoll.at(*hListIt).dispatchCB)!=NULL)
142 if (!dispatch->Call(mListPoll.at(*hListIt).handle,mListPoll.at(*hListIt).userData))
144 hListIt=hitList.erase(hListIt);
147 else //there is no dispatch function, so we just remove the file from the list...
149 hListIt=hitList.erase(hListIt);
152 } while (!hitList.empty());
157 //this was a timer event, we need to take care about the timers
166 void SocketHandler::stop_listening()
172 * Adds a filedescriptor to the polling loop
173 * @param fd this is a valid filedescriptor
174 * @param event the event flags
175 * @param callback the callback that shall be called if the filedescriptor poll succeeded
176 * @return E_OK if the descriptor was added, E_NON_EXISTENT if the fd is not valid
178 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)
180 if (!fdIsValid(fd)) return E_NON_EXISTENT;
183 pollData.pollfdValue.fd=fd;
184 pollData.handle=++mLastInsertedPollHandle;
185 pollData.pollfdValue.events=event;
186 pollData.pollfdValue.revents=0;
187 pollData.userData=userData;
188 pollData.prepareCB=prepare;
189 pollData.firedCB=fired;
190 pollData.checkCB=check;
191 pollData.dispatchCB=dispatch;
193 //add new data to the list
194 mListPoll.push_back(pollData);
196 mRecreatePollfds=true;
198 handle=pollData.handle;
203 * removes a filedescriptor from the poll loop
204 * @param fd the filedescriptor to be removed
205 * @return E_OK in case of sucess, E_NON_EXISTENT or E_UNKNOWN if the fd in not registered
207 am_Error_e SocketHandler::removeFDPoll(const sh_pollHandle_t handle)
209 mListPoll_t::iterator iterator=mListPoll.begin();
211 for (;iterator!=mListPoll.end();++iterator)
213 if(iterator->handle==handle)
215 iterator=mListPoll.erase(iterator);
216 mRecreatePollfds=true;
224 * adds a timer to the list of timers. The callback will be fired when the timer is up.
225 * This is not a high precise timer, it is very coarse. It is meant to be used for timeouts when waiting
226 * for an answer via a filedescriptor.
227 * One time timer. If you need again a timer, you need to add a new timer in the callback of the old one.
228 * @param timeouts time until the callback is fired
229 * @param callback the callback
230 * @param handle the handle that is created for the timer is returned. Can be used to remove the timer
231 * @return E_OK in case of success
233 am_Error_e SocketHandler::addTimer(const timespec timeouts,shTimerCallBack*& callback,sh_timerHandle_t& handle, void * userData)
235 assert(!((timeouts.tv_sec==0) && (timeouts.tv_nsec==0)));
236 assert(callback!=NULL);
240 //create a new handle for the timer
241 handle=++mLastInsertedHandle; //todo: overflow ruling !
242 timerItem.handle=handle;
243 timerItem.countdown=timeouts;
244 timerItem.timeout=timeouts;
245 timerItem.callback=callback;
246 timerItem.userData=userData;
248 //add timer to the list
249 mListActiveTimer.push_back(timerItem);
250 mListTimer.push_back(timerItem);
252 //very important: sort the list so that the smallest value is front
253 mListActiveTimer.sort(compareCountdown);
254 mTimeout=mListActiveTimer.front().countdown;
259 * removes a timer from the list of timers
260 * @param handle the handle to the timer
261 * @return E_OK in case of success, E_UNKNOWN if timer was not found.
263 am_Error_e SocketHandler::removeTimer(const sh_timerHandle_t handle)
267 //stop the current timer
270 std::list<timer_s>::iterator it=mListTimer.begin();
271 for(;it!=mListTimer.end();++it)
273 if(it->handle==handle)
275 it=mListTimer.erase(it);
283 * restarts a timer and updates with a new interval
284 * @param handle handle to the timer
285 * @param timeouts new timout time
286 * @return E_OK on success, E_NON_EXISTENT if the handle was not found
288 am_Error_e SocketHandler::restartTimer(const sh_timerHandle_t handle, const timespec timeouts)
291 std::list<timer_s>::iterator it=mListTimer.begin();
292 for(;it!=mListTimer.end();++it)
294 if (it->handle==handle)
301 if (timeouts.tv_nsec!=-1 && timeouts.tv_sec!=-1)
303 timerItem.timeout=timeouts;
306 mListActiveTimer.push_back(timerItem);
308 //very important: sort the list so that the smallest value is front
309 mListActiveTimer.sort(compareCountdown);
310 mTimeout=mListActiveTimer.front().countdown;
314 am_Error_e SocketHandler::stopTimer(const sh_timerHandle_t handle)
316 //go through the list and remove the timer with the handle
317 std::list<timer_s>::iterator it=mListActiveTimer.begin();
318 for(;it!=mListActiveTimer.end();++it)
320 if(it->handle==handle)
322 it=mListActiveTimer.erase(it);
323 if (!mListActiveTimer.empty())
325 mTimeout=mListActiveTimer.front().countdown;
335 return E_NON_EXISTENT;
339 * updates the eventFlags of a poll
340 * @param fd the filedescriptor of the poll
341 * @param event the event flags
342 * @return E_OK on succsess, E_NON_EXISTENT if fd was not found
344 am_Error_e SocketHandler::updateEventFlags(const sh_pollHandle_t handle, const int16_t events)
346 mListPoll_t::iterator iterator=mListPoll.begin();
348 for (;iterator!=mListPoll.end();++iterator)
350 if(iterator->handle==handle)
352 iterator->pollfdValue.events=events;
353 mRecreatePollfds=true;
361 * checks if a filedescriptor is valid
362 * @param fd the filedescriptor
363 * @return true if the fd is valid
365 bool SocketHandler::fdIsValid(const int fd) const
367 return (fcntl(fd, F_GETFL) != -1 || errno != EBADF);
371 * whenever a timer is up, this function needs to be called.
372 * Removes the fired timer, calls the callback and resets mTimeout
374 void SocketHandler::timerUp()
376 //first fire the event
377 mListActiveTimer.front().callback->Call(mListActiveTimer.front().handle,mListActiveTimer.front().userData);
379 //then remove the first timer, the one who fired
380 mListActiveTimer.pop_front();
381 if(!mListActiveTimer.empty())
383 //substract the old value from all timers in the list
384 std::for_each(mListActiveTimer.begin(),mListActiveTimer.end(),SubstractTime(mTimeout));
385 mTimeout=mListActiveTimer.front().countdown;
397 void SocketHandler::initTimer()
399 if(!mListActiveTimer.empty())
401 mTimeout=mListActiveTimer.front().countdown;
412 * convert timespec to milliseconds
413 * @param time time in timespec
414 * @return time in milliseconds
416 inline int SocketHandler::timespec2ms(const timespec & time)
418 return (time.tv_nsec == -1 && time.tv_sec == -1) ? -1 : time.tv_sec * 1000 + time.tv_nsec / 1000000;
422 * functor to easy substract from each countdown
423 * @param t value to substract from
425 void SocketHandler::SubstractTime::operator ()(timer_s & t) const
428 if((val = t.countdown.tv_nsec - param.tv_nsec) < 0){
429 t.countdown.tv_nsec = 1000000000 + val;
430 t.countdown.tv_sec--;
432 t.countdown.tv_nsec = val;
434 (t.countdown.tv_sec - param.tv_sec) < 0 ? 0 : (t.countdown.tv_sec -= param.tv_sec);
437 void SocketHandler::CopyPollfd::operator ()(const sh_poll_s & row)
439 pollfd temp=row.pollfdValue;
441 mArray.push_back(temp);