eecba5a0ad5d7249c24eed630b89d83fc1c9ae66
[profile/ivi/genivi/genivi-audio-manager.git] / AudioManagerDaemon / src / SocketHandler.cpp
1 /*
2  * SocketHandler.cpp
3  *
4  *  Created on: Dec 18, 2011
5  *      Author: christian
6  */
7
8 #include "SocketHandler.h"
9 #include <assert.h>
10 #include <sys/fcntl.h>
11 #include <sys/errno.h>
12 #include <sys/poll.h>
13 #include <algorithm>
14 #include <time.h>
15 #include <features.h>
16
17 //todo: implement ppoll
18
19 #include <iostream>  //todo remove
20
21 namespace am {
22
23 SocketHandler::SocketHandler()
24         :mMapFdCallback(),
25          mListTimer(),
26          mListPollfd(),
27          mNextTimer(),
28          mLastInsertedHandle(1),
29          mDispatch(true)
30 {
31         mTimeout.tv_nsec=-1;
32         mTimeout.tv_sec=-1;
33 }
34
35 SocketHandler::~SocketHandler()
36 {
37 }
38
39
40 //todo: maybe have some: give me more time returned?
41 /**
42  * start the block listening for filedescriptors. This is the mainloop.
43  */
44 void SocketHandler::start_listenting()
45 {
46         int pollStatus;
47
48         //init the timer
49         initTimer();
50
51         while (mDispatch)
52         {
53                 //block until something is on a filedescriptor
54                 if((pollStatus=poll(&mListPollfd.front(),mListPollfd.size(),timespec2ms(mTimeout)))==-1)
55                 {
56                         //todo enter DLT message here;
57                 }
58
59                 if (pollStatus!=0) //only check filedescriptors if there was a change
60                 {
61                         //todo: here could be a timer that makes sure naughty plugins return!
62
63                         //go through the list of fds and check if an event was set...
64                         mPollfd_t::iterator iterator=mListPollfd.begin();
65                         mPollfd_t::iterator iteratorEnd=mListPollfd.end();
66                         for(;iterator!=iteratorEnd;++iterator)
67                         {
68                                 //oh yes! then, fire the callback !
69                                 if(iterator->revents !=0)
70                                 {
71                                         //check the map for the right callback
72                                         mMapFdCallback_t::iterator iteratorCB=mMapFdCallback.begin();
73                                         iteratorCB=mMapFdCallback.find(iterator->fd);
74                                         if(iteratorCB!=mMapFdCallback.end())
75                                         {
76                                                 //fire!
77                                                 iteratorCB->second->Call(iterator->fd,iterator->events);
78                                         }
79                                 }
80                         }
81                 }
82                 else //Timerevent
83                 {
84                         //this was a timer event, we need to take care about the timers
85                         timerUp();
86                 }
87         }
88 }
89
90 /**
91  * exits the loop
92  */
93 void SocketHandler::stop_listening()
94 {
95         mDispatch=false;
96 }
97
98 /**
99  * Adds a filedescriptor to the polling loop
100  * @param fd this is a valid filedescriptor
101  * @param event the event flags
102  * @param callback the callback that shall be called if the filedescriptor poll succeeded
103  * @return E_OK if the descriptor was added, E_NON_EXISTENT if the fd is not valid
104  */
105 am_Error_e SocketHandler::addFDPoll(const int fd, const short event, TBasicPollCallback*& callback)
106 {
107         if (!fdIsValid(fd)) return E_NON_EXISTENT;
108
109         pollfd tempPollfd;
110         tempPollfd.fd=fd;
111         tempPollfd.events=event;
112         tempPollfd.revents=NULL;
113
114         //insert the filedescriptor into the poll array
115         mListPollfd.push_back(tempPollfd);
116
117         //insert the callback into the map
118         mMapFdCallback.insert(std::make_pair(fd,callback));
119         return E_OK;
120 }
121
122 /**
123  * removes a filedescriptor from the poll loop
124  * @param fd the filedescriptor to be removed
125  * @return E_OK in case of sucess, E_NON_EXISTENT or E_UNKNOWN if the fd in not registered
126  */
127 am_Error_e SocketHandler::removeFDPoll(const int fd)
128 {
129         mMapFdCallback_t::iterator iterator=mMapFdCallback.begin();
130
131         //find the filedescriptor
132         iterator=mMapFdCallback.find(fd);
133         if (iterator==mMapFdCallback.end()) return E_NON_EXISTENT;
134
135         //erase it
136         mMapFdCallback.erase(iterator);
137
138         //also remove from the callBackList
139         mPollfd_t::iterator pollIterator=mListPollfd.begin();
140         for(;pollIterator!=mListPollfd.end();++pollIterator)
141         {
142                 if (pollIterator->fd==fd)
143                 {
144                         mListPollfd.erase(pollIterator);
145                         return E_OK;
146                 }
147         }
148         return E_UNKNOWN;
149 }
150
151 /**
152  * adds a timer to the list of timers. The callback will be fired when the timer is up.
153  * This is not a high precise timer, it is very coarse. It is meant to be used for timeouts when waiting
154  * for an answer via a filedescriptor.
155  * One time timer. If you need again a timer, you need to add a new timer in the callback of the old one.
156  * @param timeouts time until the callback is fired
157  * @param callback the callback
158  * @param handle the handle that is created for the timer is returned. Can be used to remove the timer
159  * @return E_OK in case of success
160  */
161 am_Error_e SocketHandler::addTimer(const timespec timeouts,TBasicTimerCallback*& callback,timerHandle_t& handle)
162 {
163         assert(!((timeouts.tv_sec==0) && (timeouts.tv_nsec==0)));
164         assert(callback!=NULL);
165
166         timer_s timerItem;
167
168         //create a new handle for the timer
169         handle=mLastInsertedHandle++;  //todo: overflow ruling !
170         timerItem.handle=handle;
171         timerItem.countdown=timeouts;
172         timerItem.timeout=timeouts;
173         timerItem.callback=callback;
174
175         //add timer to the list
176         mListTimer.push_back(timerItem);
177
178         //very important: sort the list so that the smallest value is front
179         mListTimer.sort(compareCountdown);
180         mTimeout=mListTimer.front().countdown;
181         return E_OK;
182 }
183
184 /**
185  * removes a timer from the list of timers
186  * @param handle the handle to the timer
187  * @return E_OK in case of success, E_UNKNOWN if timer was not found.
188  */
189 am_Error_e SocketHandler::removeTimer(const timerHandle_t handle)
190 {
191         assert(handle!=0);
192
193         //go through the list and remove the timer with the handle
194         std::list<timer_s>::iterator it=mListTimer.begin();
195         for(;it!=mListTimer.end();++it)
196         {
197                 if(it->handle==handle)
198                 {
199                         it=mListTimer.erase(it);
200                         if (!mListTimer.empty())
201                         {
202                                 mTimeout=mListTimer.front().countdown;
203                         }
204                         else
205                         {
206                                 mTimeout.tv_nsec=-1;
207                                 mTimeout.tv_sec=-1;
208                         }
209                         return E_OK;
210                 }
211         }
212         return E_UNKNOWN;
213 }
214
215 /**
216  * checks if a filedescriptor is valid
217  * @param fd the filedescriptor
218  * @return true if the fd is valid
219  */
220 bool SocketHandler::fdIsValid(const int fd) const
221 {
222         return (fcntl(fd, F_GETFL) != -1 || errno != EBADF);
223 }
224
225 /**
226  * whenever a timer is up, this function needs to be called.
227  * Removes the fired timer, calls the callback and resets mTimeout
228  */
229 void SocketHandler::timerUp()
230 {
231         //first fire the event
232         mListTimer.front().callback->Call(mListTimer.front().handle);
233
234         //then remove the first timer, the one who fired
235         mListTimer.pop_front();
236         if(!mListTimer.empty())
237         {
238                 //substract the old value from all timers in the list
239                 std::for_each(mListTimer.begin(),mListTimer.end(),SubstractTime(mTimeout));
240                 mTimeout=mListTimer.front().countdown;
241         }
242         else
243         {
244                 mTimeout.tv_nsec=-1;
245                 mTimeout.tv_sec=-1;
246         }
247 }
248
249 /**
250  * inits the timers
251  */
252 void SocketHandler::initTimer()
253 {
254         if(!mListTimer.empty())
255         {
256                 mTimeout=mListTimer.front().countdown;
257         }
258         else
259         {
260                 mTimeout.tv_nsec=-1;
261                 mTimeout.tv_sec=-1;
262         }
263 }
264
265 /**
266  * convert timespec to milliseconds
267  * @param time time in timespec
268  * @return time in milliseconds
269  */
270 inline int SocketHandler::timespec2ms(const timespec& time)
271 {
272         return (time.tv_nsec==-1 && time.tv_sec==-1) ? -1 : time.tv_sec*1000 + time.tv_nsec/1000000;
273 }
274
275 /**
276  * functor to easy substract from each countdown
277  * @param t value to substract from
278  */
279 void SocketHandler::SubstractTime::operator()(timer_s& t) const
280 {
281         int val=0;
282         if((val=t.countdown.tv_nsec-param.tv_nsec)<0)
283         {
284                 t.countdown.tv_nsec=1000000000 + val;
285                 t.countdown.tv_sec--;
286         }
287         else
288         {
289                 t.countdown.tv_nsec=val;
290         }
291         (t.countdown.tv_sec-param.tv_sec)<0 ? 0 : (t.countdown.tv_sec-=param.tv_sec);
292 }
293
294
295 } /* namespace am */